Makefile 如何处理具有多个有序目标的并行make调用
GNU make允许1)并行执行和2)在同一调用中指定多个目标:Makefile 如何处理具有多个有序目标的并行make调用,makefile,gnu-make,Makefile,Gnu Make,GNU make允许1)并行执行和2)在同一调用中指定多个目标: make -j4 clean all 但是,当GNU make将目标并行化时,可能会出现一些竞争条件。说明: $ cat Makefile clean: @sleep 1 && rm -f foo all: foo @sleep 2 && cat foo foo: @echo '$@' > $@ $ make -j4 clean ; make -j4 all fo
make -j4 clean all
但是,当GNU make将目标并行化时,可能会出现一些竞争条件。说明:
$ cat Makefile
clean:
@sleep 1 && rm -f foo
all: foo
@sleep 2 && cat foo
foo:
@echo '$@' > $@
$ make -j4 clean ; make -j4 all
foo
$ make -j4 clean all
cat: foo: No such file or directory
Makefile:5: recipe for target 'all' failed
make: *** [all] Error 1
有没有一种很好的方法可以在目标之间建立一个顺序,但仍然可以从每个目标的并行加速中获益?在上面的示例中,最好等到clean
完成后再开始all
,以避免出现竞态条件
如图所示,单独的make调用按预期工作,但这并不是100%令人满意:
MAKECMDGOALS
GNU make变量和条件强制序列化多个目标:
ifeq ($(words $(MAKECMDGOALS)),1)
.PHONY: all clean
clean:
@sleep 1 && rm -f foo
all: foo
@sleep 2 && cat foo
foo:
@echo '$@' > $@
else
.NOTPARALLEL:
%:
@$(MAKE) $@
endif
当然,条件条件的条件可能更复杂,例如,测试其中一个目标是否匹配
clean
..IMHO这似乎是源于编程语言中的问题(在本例中为shell)我们能够制定出与make能够处理的依赖关系本质上不同的依赖关系。在您的示例中,clean
依赖于foo
的不存在,而all
具有相反的依赖性。如果你同时使这两个目标活跃起来,这似乎超越了制造理论的基础——我不知道是否存在一个可以处理这种关系的合理理论。我能想到的只是明确的表述:
.PHONY: all clean
clean:
@sleep 1
rm -f foo
all: foo $(filter clean,$(MAKECMDGOALS))
@sleep 2
cat foo
foo: $(filter clean,$(MAKECMDGOALS))
@echo Creating $@
@echo '$@' > $@
我认为这确实是一个有趣的问题。也许你可以打电话给
makeclean&&makeall-j4
?或者有一个特殊的rebuild
目标,该目标以以下顺序将clean
和all
作为先决条件。我不知道还有其他解决方案。@TimF不幸的是,您的重建
目标无法解决问题。在我的简单示例中,调用make-j4rebuild
时仍然会出现错误。单独的make调用是一个选项(如我最初的问题所示),但我正在寻找比指示我的makefile的任何潜在用户不支持多目标调用更好的方法……那么我想知道是否有人有其他解决方案,因为我尝试了构建设置,我也遇到了同样的问题。但我真的怀疑有没有解决办法。顺便说一下,我还将一个Makefile分发给一组用户,他们总是(直观地)在两个单独的命令中生成clean
和all
,所以在我的情况下这不是问题。@RenaudPacalet我的GNUmake失败,即使我将clean
作为all
的先决条件,因为它可能会假设从foo开始的DAG不会干扰clean的DAG,这是由于文件系统的不可见依赖关系造成的。@Vroomfondel是的,将clean
作为all
的先决条件并不能解决问题。而且,不管怎么说,即使它起作用了,那也真是太过分了:每次都必须重新构建所有内容。是的,我还尝试使用MAKECMDGOALS
。但是你用它看起来比我的好。谢谢你这个好主意。我们甚至可以通过一个额外的规则来改进它:all foo:$(filter clean,$(MAKECMDGOALS))
和所有其他不变的规则。很好的hack,太糟糕了,它不依赖于本机GNU make功能,因为它依赖于操作系统(在Unix环境中本机等待2ms这样简单的事情在Windows环境中变得很痛苦)@TimF uhh。。。我想你没有领会我和雷诺的观点。这个脚本充当依赖矛盾问题的演示者。sleep
只是一个占位符,用于“导致并行线程之间竞争条件的任何处理都会评估相互矛盾的依赖关系树”。