我有一个非常庞大且复杂的制作系统,需要几个小时才能完成。我正在研究潜在的优化方法,并且对是否可以对某些目标进行优先排序提出了疑问。
下面是一个简单的Makefile示例,说明了这一概念:
Test%: Prog%
#run some post build verification on Prog{n}
# -- takes 30min or less on failure...
Prog1: A B
# do some linking
Prog2: B C
# do some linking
A B C:
# take 10 minutes each
然后我跑
make -j2 Prog1 Test2
那么最快的构建方法是:B
和C
,然后是Prog2
和A
,然后是Test2
和{{1 }}。当然,通常,make首先会构建Prog2
和A
,这会使我的最终输出延迟10分钟。
如果我预见到B
将成为瓶颈,是否可以在gnu make中优先于该目标及其所有依赖项?
要添加到问题中,假设我正在构建Test2
,Test1
... Test2
。然后,在那种情况下,我希望其中一个目标-说Test20
尽快完成,好像失败了,我想尽快知道,以便终止构建并让其他人使用构建机器。
我考虑这样做make的单独实例:
Test1
但是,在构建测试时,make Test2 && make Prog1
将不会构建,从而导致构建服务器上的周期浪费。如果我尝试使用优先级并行构建它们:
Prog1
在构建`make Test2; nice -n -10 make Prog1`
时,这可能会导致竞争状况。
我还没有找到任何好的解决方案,但是我想我想问一下我错过了什么。 (此外,我不确定这是应该使用SO还是SuperUser -我在这里选择的是技术上的“编程”,但是请随时纠正我,我可以移动它。)
答案 0 :(得分:1)
GNU make没有提供向目标添加权重的语法。即当make能够开始下一个作业并且独立(!)目标A
和B
被解除阻止(它们的所有依赖关系都得到满足)并需要重新制作时,则取决于它们在内部的顺序建立数据库,使其首先被选择执行。
但是您可以使用其他依赖项来实现您的目标。以您的问题为例:
TESTS := Test1 Test2
$(TESTS): Test%: Prog%
Prog1: A B
Prog2: B C
ifdef _PRIORITIZE_TEST2
# additional dependencies to make sure Prog2 -> Test2 is prioritized
A: B C
endif
A B C Prog1 Prog2 Test1 Test2 all:
@echo $@
.PHONY: A B C Prog1 Prog2 $(TESTS) all
测试运行:
$ make --trace -j10 Prog1 Test2
Makefile:13: target 'A' does not exist
echo A
Makefile:13: target 'B' does not exist
echo B
Makefile:13: target 'C' does not exist
echo C
A
B
C
Makefile:13: update target 'Prog1' due to: A B
echo Prog1
Makefile:13: update target 'Prog2' due to: B C
echo Prog2
Prog1
Prog2
Makefile:13: update target 'Test2' due to: Prog2
echo Test2
Test2
$ make --trace -j10 _PRIORITIZE_TEST2=1 Prog1 Test2
Makefile:13: target 'B' does not exist
echo B
Makefile:13: target 'C' does not exist
echo C
B
C
Makefile:13: update target 'A' due to: B C
echo A
Makefile:13: update target 'Prog2' due to: B C
echo Prog2
A
Makefile:13: update target 'Prog1' due to: A B
echo Prog1
Prog2
Makefile:13: update target 'Test2' due to: Prog2
echo Test2
Prog1
Test2
这可能需要大量的手工才能获得想要的结果。您甚至可能需要编写不同组的其他依赖项,以涵盖不同的make
调用方案。
您可以考虑转储GNU make数据库(make --no-builtin-rules --print-data-base
),对其进行解析以提取所有目标及其依赖项,并可视化结果图。这是一个如何在DOT language的Graphviz中生成有向图的示例:
#!/usr/bin/perl
use warnings;
use strict;
BEGIN {
print "digraph build\n";
print "{\n";
}
my $default_goal = '???';
my @goals;
while (<STDIN>) {
if (my($target, $dependencies) = /^([\w_-]+):\s+(.*)/) {
#print "Node ${target}\n";
print " $_ -> ${target}\n"
for (split(' ', $dependencies));
} elsif (my($goals) = /^MAKECMDGOALS :=\s+(.+)/) {
@goals = split(' ', $goals);
} elsif (my($goal) = /^\.DEFAULT_GOAL :=\s+(.+)/) {
$default_goal = $goal;
}
}
END {
@goals = ( $default_goal )
unless (@goals);
#print "Root $_\n"
# for (@goals);
print "}\n";
}
exit 0;
对于上面的示例,将导致:
$ make -n --no-builtin-rules --print-data-base Prog1 Test2 2>&1 | perl dummy.pl
digraph build
{
A -> Prog1
B -> Prog1
Prog1 -> Test1
B -> Prog2
C -> Prog2
Prog2 -> Test2
}