makefile: неявные правила: одна и та же цель, разные предпосылки

У меня есть следующий make-файл:

all: DIR/0/a.txt DIR/1/b.txt DIR/2/c.txt DIR/3/abc.txt

DIR/%/abc.txt: DIR/%/def.xtx # rule #1
    mkdir -p $(@D)
    touch $@

DIR/%.txt: # rule #2
    mkdir -p $(@D)
    touch $@

DIR/%.xtx:
    touch $@

Я хочу генерировать DIR/%/def.xtx всякий раз, когда генерируется DIR/%/abc.txt; в противном случае генерировать только DIR/%.txt.

Однако при использовании make-файла с GNU Make 3.81 создается только DIR/3/abc.txt, а DIR/%/def.xtx не создается.

Следуя алгоритму поиска неявных правил в руководстве пользователя GNU make, мы получаем:

(1) Разделите t на часть каталога, названную d, и остальную часть, названную n. Например, если t равно «src / foo.o», то d равно «src /», а n - «foo.o».

Для DIR/3/abc.txt, d = DIR/3 и n = abc.txt.

(2) Составьте список всех шаблонных правил, одна из целей которых соответствует t или n. Если целевой шаблон содержит косую черту, он сопоставляется с t; в противном случае против п.

Правила №1 и №2 совпадают.

(3) Если какое-либо правило в этом списке не является правилом поиска совпадений, удалите из списка все нетерминальные правила поиска совпадений.

НЕ УВЕРЕН: ни одно правило не удалено из списка.

(4) Удалить из списка все правила без рецепта.

Ни одно правило не удалено.

(5) Для каждого шаблонного правила в списке:

(5.a) Найдите основу s, которая является непустой частью t или n, которой соответствует "%" в целевом шаблоне.

Для правила № 1 s = 3. Для правила № 2 s = 3/abc

(5.b) Вычислить предварительные имена, заменив s на «%»; если целевой шаблон не содержит косой черты, добавьте d перед каждым именем предварительного требования.

Для правила №1 это становится: DIR/3/abc.txt: DIR/3/def.xtx Правило №2 не имеет предварительных условий.

(5.c) Проверьте, все ли предпосылки существуют или должны существовать. (Если имя файла упоминается в make-файле как цель или явное предварительное условие, мы говорим, что оно должно существовать.)

НЕ УВЕРЕН: DIR/3/def.xtx упоминается правилом DIR/%.xtx:.

После этого долгого долгого объяснения я считаю, что, вероятно, ошибаюсь в (5.c).


person Adriano Carvalho    schedule 23.10.2012    source источник
comment
Возможно, я ошибаюсь, но я не думаю, что % когда-либо совпадет с чем-то с / в нем. Таким образом, предполагая, что приведенное выше - это весь ваш Makefile, у вас нет правила, которое соответствовало бы DIR/3/def.txt, и make должен жаловаться на то, что вы не знаете, как создать DIR / 3 / def.txt или что-то в этом роде.   -  person twalberg    schedule 23.10.2012
comment
[%] Действительно совпадает с /; иначе DIR/0/a.txt, DIR/1/b.txt и DIR/2/c не пострадали бы; но они это делают.   -  person Adriano Carvalho    schedule 23.10.2012
comment
Узнал что-то новое ... вроде работает. Итак, возможно, DIR/3/def.xtx не создается, потому что третьему правилу не хватает mkdir части? Поскольку это предварительное условие для DIR/3/abc.txt, его нужно сначала создать, прежде чем каталог будет существовать, поэтому mkdir в правиле 1 не произойдет, пока он не попытается запустить правило 3.   -  person twalberg    schedule 23.10.2012
comment
Да, это ошибка, но make не смотрит рецепты, чтобы определить, какие из них нужно выполнить. Если бы это сработало, touch, по крайней мере, пожаловался бы, что каталог не существует.   -  person Adriano Carvalho    schedule 23.10.2012


Ответы (1)


Из руководства,

Правило, предварительные условия которого действительно существуют или упоминаются, всегда имеет приоритет над правилом с предпосылками, которые должны быть созданы путем объединения других неявных правил.

Ваше правило №1 требует цепочки, ваше правило №2 не имеет предварительных требований, поэтому Make выберет №2 вместо №1 при попытке построить DIR/3/abc.txt.

ИЗМЕНИТЬ:

Если вы можете иметь список каталогов:

DIRS := DIR/0 DIR/1 DIR/2 DIR/3

то вы можете сделать это с помощью правила статического шаблона:

all: DIR/0/a.txt DIR/1/b.txt DIR/2/c.txt DIR/3/abc.txt

ABC_TXT := $(addsuffix /abc.txt, $(DIRS))

$(ABC_TXT): DIR/%/abc.txt : DIR/%/def.xtx

DIR/%.txt:
    mkdir -p $(@D)
    touch $@

DIR/%.xtx:
    touch $@

(И это также позволяет избежать дублирования правила .txt!)

person Beta    schedule 23.10.2012
comment
Это отвечает на вопрос, почему правило №2 выбрано вместо правила №1, но как я могу обойти это поведение ?! - person Adriano Carvalho; 23.10.2012
comment
Мы можем явно указать предварительные условия в рецепте (т.е. make DIR/$*/def.xtx), но это было бы очень неэффективно. Есть ли другой способ ?! - person Adriano Carvalho; 23.10.2012
comment
Большое спасибо! Так будет ... по крайней мере, на данный момент. :) - person Adriano Carvalho; 24.10.2012
comment
Единственная проблема с нашим решением - это необходимость указывать список каталогов. Чтобы обойти это, я сделал следующее: назначил все предварительные условия переменной (то есть ALL); то вместо $(ABC_TXT): ... я поставил ${filter DIR/%/abc.txt, $(ALL)}: DIR/%/abc.txt: DIR/%/def.xtx. Уловка здесь заключается в использовании правил статического шаблона. Большое спасибо. - person Adriano Carvalho; 24.10.2012