我有一个文件夹,其中包含未知数量的子文件夹。每个子文件夹都包含一个Dockerfile
。我想写一个Makefile
命令来批量构建以子文件夹命名的所有图像,并相应地对它们进行标记。
我首先从简单的试用开始:
build.all.images:
for f in $(find $(image_folder) -type d -maxdepth 1 -mindepth 1 -exec basename {} ;); do echo $${f}; done
当我使用硬编码的image_folder
值单独运行find
命令时,子文件夹将成功列出。然而,当我尝试运行make命令时,我只看到下面的输出:
for f in ; do echo ${f}; done
我还尝试使用ls
命令与tf
cut
链接来获得子文件夹的列表,但结果是一样的。
build.all.images:
for f in $(ls -l $(image_folder) | grep '^d' | tr -s ' ' | cut -d ' ' -f 9); do echo $${f}; done
我做错了什么?
在shell执行配方之前,它们会通过make进行扩展。因此,$(find something)
被展开,并且由于没有名为find something
的make宏,所以它被空字符串替换。将$
符号加倍(或使用反勾号(,就像对shell变量f
:所做的那样
build.all.images:
for f in $$(find $(image_folder) -type d -maxdepth 1 -mindepth 1 -exec basename {} ;); do echo $${f}; done
但在制作配方中使用for
循环通常不是一个好主意。Makefile不是shell脚本。使用您的解决方案(在修复$
问题之后(,您将无法从make的威力中获益。Make分析目标和先决条件之间的依赖关系,只重做需要重做的内容。它还具有并行功能,这对加快构建过程非常有用。
这是另一个更实用的解决方案。我改变了一些逻辑,找到Dockerfiles而不是子目录,但如果你喜欢其他方式,它很容易适应。
DOCKERFILES := $(shell find $(image_folder) -type f -name Dockerfile)
TARGETS := $(patsubst %/Dockerfile,%.done,$(DOCKERFILES))
.PHONY: build.all.images clean
build.all.images: $(TARGETS)
$(TARGETS): %.done: %/Dockerfile
printf 'sub-directory: %s, Dockerfile: %sn' "$*" "$<"
touch $@
clean:
rm -f $(TARGETS)
演示:
$ mkdir -p {a..d}
$ touch {a..d}/Dockerfile
$ make -s -j4 build.all.images
sub-directory: c, Dockerfile: c/Dockerfile
sub-directory: a, Dockerfile: a/Dockerfile
sub-directory: d, Dockerfile: d/Dockerfile
sub-directory: b, Dockerfile: b/Dockerfile
使用这种方法,只有当其Dockerfile自上次构建以来发生更改时,您才能重建映像。图像FOO
的最后构建的日期/时间是配方在构建之后创建或触摸的名为FOO.done
的空文件的最后修改日期/时间。所以,这是较少的工作要做。
此外,由于静态模式规则相当于要构建的图像的独立规则,make可以并行构建过时的图像。如果您有8个核心,请尝试make -j 8 build.all.images
,然后查看。