В каком порядке предварительные требования будут выполнены программой make GNU?

Предполагая, что у нас есть правило:

a: b c d e

и b, c, d и e не зависят друг от друга.

Определен ли порядок создания b, c, d, e? Кажется, что обычно они будут делаться по порядку b, c, d, e, но может ли случиться так, что порядок будет другим?


person peper0    schedule 30.10.2009    source источник


Ответы (7)


Конечно, если я использую make -j a, все они могут быть построены одновременно (в зависимости от того, имеют ли b, c, d или e, в свою очередь, другие / взаимосвязанные зависимости).

person Carl Norum    schedule 30.10.2009
comment
Это не совсем ответ на вопрос, поэтому я удивлен, что он был принят. - person ; 30.10.2009
comment
Вопрос, который я там прочитал: Похоже, что обычно они будут делаться по порядку b, c, d, e, но может ли случиться так, что порядок будет другим ?. Я почти уверен, что привел контрпример. Полагаю, ваше мнение может отличаться. - person Carl Norum; 30.10.2009
comment
предварительные условия только для заказа построены в определенном порядке. Однако я не уверен, что автор знал, что было что-то кроме нормальных предпосылок, основанных на его предположении. - person jww; 27.07.2014
comment
@jww нет, предварительные требования только для заказа не строятся в определенном порядке, они просто не [..] заставляют обновлять цель, если выполняется одно из этих правил [..] . - person juan.facorro; 15.06.2016

Нет, порядок не определен. В этом весь смысл использования декларативного программирования, ориентированного на зависимости: компьютер может выбрать оптимальный порядок оценки или, фактически, оценить их даже одновременно.

person Jörg W Mittag    schedule 30.10.2009

В каком порядке предварительные требования будут выполнены программой make GNU?

Это зависит от типа предпосылки. Согласно GNU Make Manual, раздел 4.2:

На самом деле GNU make понимает два разных типа предварительных условий: обычные предварительные условия, такие как описанные в предыдущем разделе, и предварительные требования только для порядка. Обычное предварительное условие состоит из двух утверждений: во-первых, оно устанавливает порядок, в котором рецепты будут вызываться: рецепты для всех предварительных условий цели будут выполнены до того, как рецепт для цели будет запущен. Во-вторых, он устанавливает отношения зависимости: если какое-либо предварительное условие новее, чем цель, то цель считается устаревшей и должна быть перестроена.

Обычно это именно то, что вам нужно: если предварительное условие цели обновлено, то цель также должна быть обновлена.

Однако иногда возникает ситуация, когда вы хотите наложить определенный порядок на правила, которые будут вызываться без принудительного обновления цели, если выполняется одно из этих правил. В этом случае вы хотите определить предварительные требования только для заказа. Предварительные условия только для заказа можно указать, поместив вертикальную черту (|) в список предварительных требований: любые предварительные условия слева от вертикальной черты являются нормальными; любые предварительные условия справа относятся только к заказу:

   targets: normal-prerequisites | order-only-prerequisites

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

Рассмотрим пример, в котором ваши цели должны быть помещены в отдельный каталог, и этот каталог может не существовать до запуска make. В этой ситуации вы хотите, чтобы каталог был создан до того, как в него будут помещены какие-либо цели, но, поскольку временные метки в каталогах меняются всякий раз, когда файл добавляется, удаляется или переименовывается, мы, конечно, не хотим перестраивать все целевые объекты всякий раз, когда метка времени каталога изменяется. Один из способов справиться с этим - использовать предварительные условия только для заказа: сделать каталог предварительным условием только для заказа для всех целей:

OBJDIR := objdir
OBJS := $(addprefix $(OBJDIR)/,foo.o bar.o baz.o)

$(OBJDIR)/%.o : %.c
    $(COMPILE.c) $(OUTPUT_OPTION) $<

all: $(OBJS)

$(OBJS): | $(OBJDIR)

$(OBJDIR):
    mkdir $(OBJDIR)

Теперь правило для создания каталога «objdir» будет выполняться, если необходимо, до создания любого «.o», но «.o» не будет построено, поскольку временная метка каталога «objdir» изменилась.

person jww    schedule 27.07.2014
comment
Однако на самом деле это не требует упорядочивания, по крайней мере, не более чем обычное предварительное условие. Он просто говорит, что для предварительного требования только для заказа gmake должен игнорировать временную метку. Это предварительное условие, поэтому оно должно существовать до того, как текущее правило может быть запущено, но, поскольку это предварительное условие только для заказа, его временная метка / состояние не запускает текущее правило. (Что не исключает наличия других зависимостей, из-за которых зависимости только для порядка выполнения своих команд.) - person simpleuser; 19.03.2015
comment
Из документации gnu make, приведенной выше: Occasionally, however, you have a situation where you want to impose a specific ordering on how the rules of a target are going to be invoked without forcing the target to be updated if one of those rules is executed. Это кажется довольно неуместным в отношении того, что на самом деле делает предварительное условие только для oder. Насколько я понимаю, предварительное условие только для заказа - это просто предварительное условие, которое не заставляет make перестраивать цель, если она изменится. - person SebNag; 06.10.2017
comment
Я думаю, что это не то, что искала OP. Попробуйте вызвать make -j, чтобы узнать, действительно ли зависимости выполняются в ожидаемом вами порядке. - person dubbaluga; 22.02.2021

В правом порядке в соответствии с указанными вами правилами. В вашем конкретном примере это может означать любой из нескольких различных (4! = 24, из памяти) заказов.

Все make программы могут свободно выбирать порядок, который им нравится, если соблюдаются зависимости. Если бы в вашем примере были другие правила, скажем c: b, тогда c было бы сделано до b (но это не так, как вы указываете).

Если вам нужно полагаться на определенный порядок, вам потребуется больше правил для его соблюдения. В противном случае make может делать то, что ему заблагорассудится. В документации для GNU Make только указано, как правила обрабатываются, а не в том порядке, в котором обрабатываются зависимости в правиле. Наиболее логичным (для меня, во всяком случае) будет порядок, в котором они перечислены, но это не гарантируется.

person paxdiablo    schedule 30.10.2009

Нет, вы не можете рассчитывать на упорядочение, когда нет отношений зависимости.

  • make необходимо выполнить топологическую сортировку, поскольку зависимости могут иметь дополнительные и множественные отношения. Сортировка, которую выполняет make, потенциально довольно сложна, поскольку узлы в графе могут быть связаны несколько раз на разных уровнях.
  • обычно алгоритмы сортировки не являются стабильными даже для простые сортировки на основе ключей
person DigitalRoss    schedule 30.10.2009

Я просто добавлю это для справки в будущем. Хотя GNU Make может не определять конкретный порядок, когда дело доходит до предварительных условий обработки, POSIX make требует, чтобы они обрабатывались в том порядке, в котором они были указаны, а именно слева направо. Большинство реализаций следуют этому правилу. POSIX даже дает пример, когда реализация make, не следуя этому правилу, может нарушить процесс сборки программы:

foo: y.tab.o lex.o main.o
    $(CC) $(CFLAGS) -o $@ t.tab.o lex.o main.o

где lex.o в конечном итоге использует неверный y.tab.h. Хотя это можно переписать способом, который работает с GNU Make, я подумал, что поделюсь этим лакомым кусочком о порядке предварительных требований.

person Bogdan Barbu    schedule 02.02.2020

Если порядок имеет значение, вы можете выборочно применить его с помощью рекурсивного make. . Например, предположим, что вам все равно, в каком порядке выполняются b и c, если они оба сделаны до того, как d, а d - до e. Тогда вы могли бы написать свое правило как:

a: b c
    $(MAKE) d
    $(MAKE) e
    # Additional steps to make a

Имейте в виду, что в зависимости от сложности d и e этот подход может плохо сказаться на времени сборки: см. Рекурсивное объявление считается вредным (PDF) за аргументы против этого.

person Simon Brady    schedule 02.10.2017