我有一个如下的 Makefile,我关心
up-clean
的依赖顺序:
.PHONY: up
up: down
docker-compose up -d
.PHONY: up-clean
up-clean: down-clean up
.PHONY: down
down:
docker-compose down
.PHONY: down-clean
down-clean:
docker-compose down -v
显然重要的是,在
up-clean: down-clean up
中,down-clean
必须在up
之前执行。对于普通的 make 目标,解决方案是添加一个条目 up: down-clean
,但由于这些是 PHONY 目标,这将使 up
在功能上等同于 up-clean
,每次都会删除卷。显然,这是不可接受的。
实际上,GNU make 尊重依赖关系的顺序,但它不保证这一点,因此并不完全值得信赖,或者说
-j
根本不值得信赖。在这种情况下,有什么方法(如果有的话)可以确保依赖项的执行顺序而不改变构建其他目标的结果?
编辑:尝试使用仅订单先决条件似乎不起作用,可能是因为与
.PHONY
的交互。添加
up: | down-clean
导致执行日志为:
$ make up
docker-compose down
<...>
docker-compose down -v
Removing volume <...>
这是正常先决条件应该发生的情况,而不是仅限订单的先决条件。
最简单的答案是使用 make 的递归调用:
up-clean:
$(MAKE) down-clean
$(MAKE) up
从 GNU make 4.4 开始,您可以使用
.WAIT
伪目标显式序列化您的先决条件,例如,
.PHONY: up-clean
up-clean: down-clean .WAIT up
在 4.4 之前,GNU Make 文档没有对启用并行执行的顺序或执行做出任何承诺。但是,任何符合 POSIX 标准的 make 实现(重点是我的) ...应将所有先决条件视为目标本身,并递归地确保它们是最新的,
按照它们在规则中出现的顺序处理它们。 make 实用程序应使用文件的修改时间来确定相应的目标是否已过期。但是,4.4版本还添加了当然,在并行模式下,GNU make 并不能完全符合这个要求。
--shuffle
该选项的实现者所做的研究
来看,很明显,非确定性的唯一来源是
-j
选项和并行模式执行情况,补丁和测试的内容也证明了这一点,并由 GNU make 项目的其他成员进行了审查。
因此,在4.4之前的版本中,我们可以放心地假设,只要make以非并行模式执行,先决条件就会严格按照指定的顺序从左到右执行。在 4.4 之前的版本中,我们可以使用
.NOTPARALLEL
伪目标禁用并行性,只需将其添加到您的文件中,例如,
.NOTPARALLEL: # ensures that all deps are executed strictly in order
.PHONY: up
up: down
docker-compose up -d
.PHONY: up-clean
up-clean: down-clean up
.PHONY: down
down:
docker-compose down
.PHONY: down-clean
down-clean:
docker-compose down -v
另请注意,--shuffle
尊重
.NOTPARALLEL
目标的存在,这证实了我们的假设:顺序可能与语法顺序不同只是因为并行执行。
另一种选择是在 up
进行建模,而不是将后者作为前者的先决条件:
.PHONY: up
up: down
docker-compose up -d
.PHONY: up-clean
up-clean: down-clean
docker-compose up -d
如果你想让它变得更干燥,你可以将 docker-compose
命令分解为变量:
UP_COMMAND = docker-compose up -d
.PHONY: up
up: down
$(UP_COMMAND)
.PHONY: up-clean
up-clean: down-clean
$(UP_COMMAND)