Можете ли вы определить приоритетность целей make-файла? - PullRequest
0 голосов
/ 15 февраля 2019

У меня очень большая и замысловатая система изготовления, для завершения которой требуются часы.Я исследую потенциальные оптимизации, и у меня возник вопрос о том, можно ли расставить приоритеты для определенных целей.

Вот пример простого 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 и Prog2.Конечно, обычно make сначала собирает A и B, что задерживает мой окончательный вывод на 10 минут.

Если я заранее знаю, что Test2 будет узким местом, верно?Можно ли расставить приоритеты для этой цели и всех ее зависимостей над другими целями в gnu make?

Чтобы добавить к вопросу, допустим, я строю Test1, Test2 ... Test20.Тогда в этом случае я бы хотел, чтобы одна из целей - скажем, Test1 была выполнена как можно скорее, как если бы это не удалось, я хотел бы знать как можно скорее, чтобы я мог прекратить сборку и позволитькто-то другой использует сборочную машину.

Я рассмотрел возможность создания отдельных экземпляров make следующим образом:

make Test2 && make Prog1

Но, пока идет сборка теста, Prog1 не будет собираться, в результате чегов потраченных впустую циклах на сервере сборки.Если бы я попытался построить их параллельно с приоритетами:

`make Test2; nice -n -10 make Prog1`

Это может привести к условиям гонки при сборке B.

Я еще не нашел каких-либо хороших решений, но я решил спросить на случай, если что-то пропустил.(Кроме того, я не уверен, должно ли это быть на SO или SuperUser - я выбрал здесь, поскольку это технически о «программировании», но, пожалуйста, не стесняйтесь исправлять меня, и я могу переместить это).

1 Ответ

0 голосов
/ 16 февраля 2019

GNU make не предлагает синтаксиса для добавления веса к цели.Т.е. когда make может запустить следующее задание, а независимые (!) Цели A и B разблокированы (все их зависимости выполнены) и требуют переделки, то это зависит от их порядка во внутренней базе данных make, котораяодин выбирается первым для выполнения.

Но вы можете использовать дополнительные зависимости для достижения своей цели.Чтобы взять пример из вашего вопроса:

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 из 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
}
...