Рекурсивната make рекурсира твърде много и изисква фиктивна предпоставка

Имам много прост Makefile, който не прави това, което очаквам да направи. Крайната цел е той да се извиква рекурсивно, включително съответния файл всеки път, което води до компилация, специфична за това, което е включено (изграждам няколко проекта, които споделят една и съща кодова база, но използват различни комбинации от изходни файлове ). Никога не съм се занимавал с рекурсивни повиквания, така че трябва да пропускам нещо очевидно. В момента имам само един .mk файл в същата папка като моя Makefile. Това е прост едноредов само за целите на този тест. В крайна сметка ще съдържа различни настройки за всеки проект.

Makefile:

SHELL = /bin/sh

ifdef MYFILE
include $(MYFILE)
PROGRAM = $(basename $(MYFILE))
endif

all: $(wildcard *.mk)

dummy:
        @echo -- Entering dummy stub ... why do I need this?

%.mk: dummy
        @echo Calling $(MAKE) MYFILE=$@ $*
        $(MAKE) MYFILE=$@ $*

$(PROGRAM): objs
        @echo Time to link!

objs:
        @echo Building objs!

test.mk

SOMEVAR = SomeValue

Имам следните два проблема:

Проблем 1

Ако премахна предпоставката dummy от моето правило за шаблон, правилото за шаблон никога не се извиква (получавам страховитата грешка „Нищо не трябва да се прави за всички“). Има ли начин да накарам рецептите под правилото %.mk да се изпълняват, без да се нуждая от тази фиктивна предпоставка?

Проблем 2

Имайки предвид двата гореспоменати файла, бих очаквал make да направи следното:

  1. make[1] стартира и натиснете правилото all
  2. make[1] скача надолу към правилото за шаблон %.mk
  3. make[1] се извиква рекурсивно (извикването ще изглежда като make MYFILE=test.mk test)
  4. make[2] стартира, включва файла test.mk и настройва променливата PROGRAM
  5. make[2] скача надолу към правилото $(PROGRAM) (тъй като бяхме изрично извикани с тази цел)
  6. make[2] прескача до правилото objs, изпълнява рецептите и се връща обратно по веригата

В действителност make се забива в правилото за шаблон %.mk и влиза в безкраен цикъл. Не разбирам защо настоява да изпълни правилото за шаблон, когато изрично му казах да изгради test в първото ми рекурсивно повикване (което трябва да съответства на целта $(PROGRAM)). Какво ми липсва тук?


person Jonah Bishop    schedule 04.05.2012    source източник
comment
До какво мислите, че ще се разшири $(PROGRAM) при първото извикване на make? Има ли значение? Второ, make прави две преминавания през make-файла, за да разреши/оцени всички променливи. Ще съдържат ли това, което очаквате, когато влезете в рекурсивното повикване?   -  person HonkyTonk    schedule 04.05.2012
comment
За мен няма значение какво оценява $(PROGRAM) при първото извикване; това правило никога не трябва да се изпълнява, освен ако не е изрично извикано. Вярвам, че стойностите трябва да включват това, което очаквам при второто преминаване, но има ли прост начин да тествам това?   -  person Jonah Bishop    schedule 04.05.2012


Отговори (1)


Проблем 0:
Това е прекалено проектирано. Не е необходимо да използвате рекурсивно Make тук.

Проблем 1:
Причината, поради която Make не се опитва да възстанови test.mk (без фиктивен preq), е, че test.mk е актуален. По-добър подход е да преминете към правило за статичен шаблон и да използвате PHONY:

MKS = $(wildcard *.mk)
.PHONY: $(MKS)

$(MKS): %.mk:
    @echo Calling $(MAKE) MYFILE=$@ $*
    $(MAKE) MYFILE=$@ $*

Още по-добър подход е да не използвате името на истински файл като цел на правило, което не възстановява (или дори не „докосва“) този файл.

Проблем 2:
В make[2] make-файлът включва test.mk. Ако makefile включва друг файл, Make ще се опита да възстанови този файл, преди да направи нещо друго. Ако има правило за този файл (което има) и ако той успее (което е така), Make след това се извиква отново.

Трябва да преразгледате този дизайн от самото начало. Има много начини да получите поведението, което търсите, в зависимост от спецификата (колко променливи ще бъдат дефинирани в foo.mk? наистина ли искате да управлявате компилацията чрез ръчно преместване на тези файлове? и т.н.).

P.S. Ето една глупост, която ми идва наум. Дали е подходящо за вашия случай зависи от спецификата:

makefile:

# includes nothing

%.mk: dummy
        @echo Calling $(MAKE) MYFILE=$@ -f $@ $*
        $(MAKE) MYFILE=$@ -f $@ $*

test.mk:

SOMEVAR = SomeValue
include makefile
person Beta    schedule 04.05.2012
comment
Благодаря за предложенията. Страхувах се, че се опитвам да стана твърде изящен. Ще преработя това, което се опитвам да направя, и ще използвам нещо много по-просто. - person Jonah Bishop; 04.05.2012
comment
Радвам се, че мога да помогна. Ако искате повече помощ/съвет/предложения, не се колебайте да попитате. - person Beta; 04.05.2012