makefile: имплицитни правила: същата цел различни предпоставки

Имам следния makefile:

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; в противен случай срещу n.

Правила #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 на променлива (т.е. ALL); тогава вместо $(ABC_TXT): ..., поставих ${filter DIR/%/abc.txt, $(ALL)}: DIR/%/abc.txt: DIR/%/def.xtx. Номерът тук е използването на статични правила за шаблони. Благодаря много. - person Adriano Carvalho; 24.10.2012