我可能有错误的术语,请随时纠正我。一段时间以来,我们一直在滥用 make 来完成许多构建。 99% 的情况下,这是使用虚假目标。我们有 docker 构建项目,我们为每个版本化的 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 单独处理所有构建,您有可能可以做得更好。 静态模式规则示例:
DOCKERFILES := $(wildcard */Dockerfile)
LINTS := $(addprefix lint-,$(DOCKERFILES))
INITS := $(addprefix init-,$(DOCKERFILES))
BUILDS := $(addprefix build-images-,$(DOCKERFILES))
.PHONY: all lint init build-images $(LINTS) $(INITS) $(BUILDS)
all: lint init build-images
lint: $(LINTS)
$(LINTS): lint-%: %
$(call dockerLint,$<,$(_DOCKER_BUILD_ARCH))
init: $(INITS)
$(INITS): init-%: %
$(call initVariablesForImage,$<)
build-images: $(BUILDS)
$(BUILDS): build-images-%: %
$(call dockerBuildPush,$<,$(_DOCKER_BUILD_ARCH))
这样做的优点之一是 make 可以并行运行配方。如果您有 12 个核心,请尝试
make -j12
,看看...
但这并不是最优的,因为它没有指定每个配方会产生什么。 make 无法决定产品的依赖项是否是最新的。每次您致电
make all
时,所有食谱都会重建,而有些食谱可能是最新的。您的问题未包含足够的信息来提出更有效的解决方案。