我可能用错了术语,所以请随时纠正我。我们一段时间以来一直在滥用 make 进行大量构建。99% 的时间都是使用虚假目标。我们有 docker build 项目,我们为每个版本化的 docker 文件调用 docker build。文件结构看起来像这样:
6/Dockerfile
8/Dockerfile
获取项目中的 docker 文件列表很容易。
DOCKERFILES:=$(wildcard */Dockerfile)
目前我们正在使用这种方法来构建docker文件:
.PHONY: all
all: lint init build-images
.PHONY: lint
lint:
$(foreach image, $(DOCKERFILES),$(call dockerLint,$(image),$(_DOCKER_BUILD_ARCH)))
.PHONY: init
init:
$(foreach image, $(DOCKERFILES),$(call initVariablesForImage,$(image)))
.PHONY: build-images
build-images:
$(foreach image, $(DOCKERFILES),$(call dockerBuildPush,$(image),$(_DOCKER_BUILD_ARCH)))
但是,为了更好地理解 make 并避免 foreach,是否可以定义与 Dockerfile 匹配的多个规则并运行相关配方?我使用单个规则取得了一些成功,但一旦我尝试执行多个配方,它就会失败。
.PHONY: test
test: $(DOCKERFILES)
$(DOCKERFILES):*
$(info ***** build $@)
输出结果如下:
***** build 6/Dockerfile
***** build 8/Dockerfile
我预计这种方法是错误的,因为当我尝试引入其他目标时,我会收到覆盖警告或循环引用:
warning: overriding commands for target `8/Dockerfile'
warning: ignoring old commands for target `8/Dockerfile'
...
make: Circular 6/Dockerfile <- 6/Dockerfile dependency dropped.
make: Circular 7/Dockerfile <- 7/Dockerfile dependency dropped.
make: Circular 8/Dockerfile <- 8/Dockerfile dependency dropped.
我想停下来看看我想要实现的目标是否可行。我们现有的方案是可行的,但探索替代方案以查看我们能否提出更清晰的实现方案会更好。
通常,当您编写一个循环遍历多个构建的配方时,让 make 分别处理所有构建可能会让您做得更好。静态模式规则的示例:
其中一个优点是 make 可以并行运行配方,而配方中的循环是连续的。
make -j12
如果您有 12 个核心,请尝试一下,看看...警告
lint
:如果、init
和步骤之间存在依赖关系build
,则应指定它们。您的问题没有包含足够的信息来提出解决方案,但如果应在 之前和之前lint
运行,您可以调整和 的静态模式规则:init
init
build
init
build
重要提示:由于我们只使用虚假目标,因此每次运行时都会重建所有内容
make all
。但如果 make 知道每个规则的输入(配方使用的文件)和产品(配方创建或更新的文件),它就可以做得更好。有了所有这些,make 可以比较输入和产品的最后修改日期,以决定是否必须运行配方,或者如果运行配方则毫无用处,因为产品相对于输入是最新的。您的问题没有包含足够的信息来提出解决方案。