GNU make允许1)并行执行和2)在同一个调用中指定几个目标:
make -j4 clean all
但是,由于GNU使目标并行化,因此可能会出现一些竞争条件。插图:
$ 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%令人满意:
答案 0 :(得分:1)
恕我直言,这似乎根源于一个问题,即在编程语言(在本例中为shell)中,我们能够形成依赖性,这些依赖性与make可以处理的性质有着根本不同的性质。在您的示例中,clean
与foo
的不存在存在依赖关系,而all
具有逆依赖关系。如果你同时激活这两个目标,这似乎超越了make的理论基础 - 我不知道是否存在能够处理这种关系的合理理论。我能提出的一切都是明确的表述:
.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 '$@' > $@
我认为这肯定是一个有趣的问题。
答案 1 :(得分:0)
我找到了一种解决方法(但我并不是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
...