Предварительные требования только для заказа не работают корректно в GNU?

У меня проблема с предварительными условиями только для заказа. Они не выполняются в первую очередь. Неужели я неправильно понимаю, как работают предварительные условия для заказа?

Далее сделайте script:

.PHONY: mefirst mefirst2

mefirst:
    @echo "I'm first!"

mefirst2:
    @echo "I'm first too!"

normaltarget: normaltarget2 | mefirst2
    @echo "normaltarget done"

normaltarget2: a b c 
    @echo "normaltarget2 done"

helloworld: normaltarget | mefirst
    @echo "helloworld done"

.DEFAULT_GOAL := go
go: helloworld
    @echo "go done"

a:
    @echo a
b:
    @echo b
c:
    @echo c

... выводит следующее:

a
b
c
normaltarget2 done
I'm first too!
normaltarget done
I'm first!
helloworld done
go done

... вместо того, что я ожидал бы:

I'm first!
I'm first too!
a
b
c
normaltarget2 done
normaltarget done
helloworld done
go done

Что я делаю неправильно?

Ответы

Ответ 1

Я неправильно понимаю, как работают предпосылки только для заказа?

Да, вот как это выглядит.

Название "только для заказа" несколько сбивает с толку. Предпосылки позади | называются "предварительными условиями только для заказа" не потому, что они изменяют порядок выполнения рецепта в списке предварительных условий для одной цели, а потому, что их единственная цель состоит в том, чтобы определенные цели создавались раньше других, например, при начальной загрузке. Как точно объяснено пользователем bobbogo ниже (- спасибо за исправление): если make решит перестроить предварительное условие для цели, он запустит рецепт для этого предварительного условия. Теперь для обычной предпосылки это обновление подразумевает, что цель устарела, и make придется запустить целевой рецепт. С другой стороны, для обязательного предварительного заказа make не помечает цель как нуждающуюся в обновлении.

Например, см. Раздел " Типы предпосылок" для варианта использования, в котором каталог должен быть создан до создания объектов в этом каталоге.

Возьмите этот пример makefile:

a: b
    touch a

b: c
    touch b

c:
    touch c

x: | y 
    touch x

y: | z 
    touch y

z:
    touch z

Как вы можете видеть, b и c являются нормальными предпосылками для a и b, тогда как y и z являются предпосылками только для порядка для x и y. Начиная с чистого листа, они выглядят одинаково:

:~$ make a
touch c
touch b
touch a
:~$ make x
touch z
touch y
touch x
:~$ make a
make: 'a' is up to date.
:~$ make x
make: 'x' is up to date.

Однако, если мы теперь вручную "обновим" предварительные условия в конце цепочки (c и z), мы увидим разницу:

:~$ touch c
:~$ make a
touch b
touch a
:~$ touch z
:~$ make x
make: 'x' is up to date.

Это показывает, как существующие предварительные условия только для заказа не делают недействительными какие-либо цели, независимо от их отметки времени. Однако удаление цели только для заказа приводит к перестройке (но только перестройке этого отсутствующего файла):

:~$ rm c
:~$ make a
touch c
touch b
touch a
:~$ rm z
:~$ make x
touch z

Тем не менее, правильный способ изменить порядок запуска ваших рецептов - исправить зависимости между целями. Например, если вы хотите, чтобы mefirst был построен перед a, то вам нужно сделать mefirst обязательным условием для a, как в

a: mefirst
    @echo a

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


В вашем ответе есть ярлык, который не является решением, но все же интересно узнать. Хотя это и не задокументировано, кажется, что предпосылки для одной цели обрабатываются в том порядке, в котором они появляются. | знак не меняет этого. В вашем простом случае вы можете воспользоваться этим, чтобы получить результат, который вы ищете:

normaltarget: mefirst2 normaltarget2
    @echo "normaltarget done"

а также

helloworld: mefirst normaltarget
    @echo "helloworld done"

Однако, как вы сами указали, это "решение" ломается, как только флаг -j используется для параллельного запуска рецептов. Кроме того, как указал пользователь bobbogo, полагаться на этот механизм упорядочения - плохая практика. Введение новых зависимостей может помешать упорядочению. Так что не делай этого :-)