2017-09-29 89 views
2

GNU化妆允许1)并行执行和2)指定在同一调用几个目标:如何处理多个并行make调用命令的目标

make -j4 clean all 

但是,作为GNU使并行化的目标,一些竞争条件可能发生。插图:

$ cat Makefile 
clean: 
    @sleep 1 && rm -f foo 

all: foo 
    @sleep 2 && cat foo 

foo: 
    @echo '[email protected]' > [email protected] 
$ 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 

有没有一种很好的方式来强制目标之间的顺序,但仍然受益于每个目标的并行加速?在上面的例子中,为了避免竞争条件,等待cleanall开始之前完成将是很好的。

如图所示,单独建立调用按预期工作,但这不是100%满意:

  1. 有些目标可以同时调用,有些则不能。因此完全禁止多个目标可以被认为是太严格。但是识别所有有效和无效的组合是棘手和容易出错的。
  2. 为了完全避免这个问题,可以警告所有这样的Makefile的潜在用户在并行模式下不支持多个目标调用,但是这个警告将不可避免地被某些用户忽略。
  3. 比赛条件并不总是会导致错误。有些显然可以无缝工作,但会产生错误的结果。
+0

也许你可以直接调用'make clean && make all -j4'?或者有一个特殊的'rebuild'目标,它的顺序是'clean'和'all'作为先决条件。我不知道其他解决方案。 – Tim

+0

@TimF不幸的是,你的'rebuild'目标不能解决问题。在我的简单示例中,调用'make -j4 rebuild'时仍然出现错误。而单独的make调用是一个选项(如我原来的问题所示),但我正在寻找一些东西,比指示我的Makefiles的任何潜在用户不支持多个目标调用... –

+0

那么我会好奇的看看是否有人有另一种解决方案,因为我尝试了我的构建设置和我有同样的问题。但我真的怀疑有一个解决方案。顺便说一下,我也将Makefile分发给一组用户,他们总是(直观地)用两个单独的命令来创建'clean'和'all',所以在我的情况下这不是问题。 – Tim

回答

1

恕我直言,这似乎是根源于在编程语言(在这种情况下,壳)的问题,我们能够制定的依赖关系,它们的性质基本上不同于那些可以处理。在您的示例中,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 [email protected] 
    @echo '[email protected]' > [email protected] 

我认为这确实是一个有趣的问题。

+0

是的,我也尝试使用'MAKECMDGOALS'。但是你的使用看起来比我的好。感谢这个好主意。我们甚至可以用一个额外的规则来改进它:'all foo:$(filter clean,$(MAKECMDGOALS))',其他所有其他规则不变。 –

+0

不错的黑客,太糟糕了,它不依赖于本地的GNU make功能,因为它变得依赖于操作系统(和在Unix环境中原生等待2ms一样简单的事情成为Windows环境中的痛苦) – Tim

+0

@TimF uhh ..我想你错过了我和雷诺兹的观点。这个剧本就像是依赖性矛盾问题的示范者。 “sleep”仅仅是“任何处理导致评估矛盾依赖树的并行线程之间的竞争条件”的占位符。 – Vroomfondel

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 '[email protected]' > [email protected] 
else 
.NOTPARALLEL: 

%: 
    @$(MAKE) [email protected] 
endif 

当然,有条件的情况可能会更复杂,比如,举例来说,如果一个测试目标匹配clean ...

相关问题