仅当需要构建依赖项时才执行 Makefile 目标

时间:2021-07-07 17:36:36

标签: makefile

我有一个包含两个“子项目”和一个 Dockerfile 的项目,该 Dockerfile 组合了来自每个子项目的可执行文件。目录结构是这样的:

Makefile
Dockerfile
proj1/Makefile
proj1/proj1-bin
proj1/...
proj2/Makefile
proj2/proj1-bin
proj2/...

我的顶级 Makefile 目前是这样的:

container: proj1 proj2
  docker build .

proj1:
  make -C proj1

proj2:
  make -C proj2

.PHONY: container proj1 proj2

如何才能使容器仅在重建 proj1 或 proj2 时重建?

1 个答案:

答案 0 :(得分:0)

当一个目标被标记为 .PHONY 时,它总是会被重建,所以首先要摆脱虚假目标并依赖于实际文件,这些文件具有要比较的时间戳。唯一的问题是如何发现一个容器已经构建;一种处理方法是在构建容器时创建时间戳文件 - 这将仅作为 make 在决定是否重建目标时进行比较的时间戳。

时间戳文件应依赖于子项目中创建的实际文件,以便将 docker build 时间戳与实际二进制文件进行比较,如果实际二进制文件较新,则将重建容器。子项目反过来需要始终委托给 $(MAKE),因为只有子 Makefile 知道如何以及是否重建目标。我们可以通过依赖虚假目标来实现这一点,这将使配方运行,但最终,如果文件本身没有得到更新,它不会触发更高级别目标(container.timestamp 文件,因此容器不会被重建)。

示例:

$ cat Makefile
.PHONY: container
container: container.timestamp

container.timestamp: proj1/proj1.bin proj2/proj2.bin
        echo docker build .
        touch $@

%.bin: FORCE
        $(MAKE) -C $(@D)

.PHONY: FORCE

$ cat proj1/Makefile
proj1.bin:
        touch $@

$ cat proj2/Makefile
proj2.bin:
        touch $@

输出:

$ make
make -C proj1
make[1]: Entering directory '/mnt/c/Users/raspy/git/so-68290730/proj1'
touch proj1.bin
make[1]: Leaving directory '/mnt/c/Users/raspy/git/so-68290730/proj1'
make -C proj2
make[1]: Entering directory '/mnt/c/Users/raspy/git/so-68290730/proj2'
touch proj2.bin
make[1]: Leaving directory '/mnt/c/Users/raspy/git/so-68290730/proj2'
echo docker build .
docker build .
touch container.timestamp

$ make
make -C proj1
make[1]: Entering directory '/mnt/c/Users/raspy/git/so-68290730/proj1'
make[1]: 'proj1.bin' is up to date.
make[1]: Leaving directory '/mnt/c/Users/raspy/git/so-68290730/proj1'
make -C proj2
make[1]: Entering directory '/mnt/c/Users/raspy/git/so-68290730/proj2'
make[1]: 'proj2.bin' is up to date.
make[1]: Leaving directory '/mnt/c/Users/raspy/git/so-68290730/proj2'

注意子生成文件是如何被调用的,但由于二进制文件没有更新,容器也没有更新。但是,如果此更新,则将重建容器:

$ touch proj2/proj2.bin
$ make
make -C proj1
make[1]: Entering directory '/mnt/c/Users/raspy/git/so-68290730/proj1'
make[1]: 'proj1.bin' is up to date.
make[1]: Leaving directory '/mnt/c/Users/raspy/git/so-68290730/proj1'
make -C proj2
make[1]: Entering directory '/mnt/c/Users/raspy/git/so-68290730/proj2'
make[1]: 'proj2.bin' is up to date.
make[1]: Leaving directory '/mnt/c/Users/raspy/git/so-68290730/proj2'
echo docker build .
docker build .
touch container.timestamp