您可以确定makefile目标的优先级吗?

时间:2019-02-15 15:15:38

标签: makefile gnu-make

我有一个非常庞大且复杂的制作系统,需要几个小时才能完成。我正在研究潜在的优化方法,并且对是否可以对某些目标进行优先排序提出了疑问。

下面是一个简单的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

那么最快的构建方法是:BC,然后是Prog2A,然后是Test2和{{1 }}。当然,通常,make首先会构建Prog2A,这会使我的最终输出延迟10分钟。

如果我预见到B将成为瓶颈,是否可以在gnu make中优先于该目标及其所有依赖项?

要添加到问题中,假设我正在构建Test2Test1 ... Test2。然后,在那种情况下,我希望其中一个目标-说Test20尽快完成,好像失败了,我想尽快知道,以便终止构建并让其他人使用构建机器。

我考虑这样做make的单独实例:

Test1

但是,在构建测试时,make Test2 && make Prog1 将不会构建,从而导致构建服务器上的周期浪费。如果我尝试使用优先级并行构建它们:

Prog1

在构建`make Test2; nice -n -10 make Prog1` 时,这可能会导致竞争状况。

我还没有找到任何好的解决方案,但是我想我想问一下我错过了什么。 (此外,我不确定这是应该使用SO还是SuperUser -我在这里选择的是技术上的“编程”,但是请随时纠正我,我可以移动它。)

1 个答案:

答案 0 :(得分:1)

GNU make没有提供向目标添加权重的语法。即当make能够开始下一个作业并且独立(!)目标AB被解除阻止(它们的所有依赖关系都得到满足)并需要重新制作时,则取决于它们在内部的顺序建立数据库,使其首先被选择执行。

但是您可以使用其他依赖项来实现您的目标。以您的问题为例:

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 languageGraphviz中生成有向图的示例:

#!/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
}