Как да генерирам правило за Makefile

Искам да генерирам правила в Makefile по следния начин:

# $(call cc-defs, ccfiles)
define cc-defs
    $1.files = $(patsubst %.cc,%.proto,$1)
    $1: $1.files
endef
$(foreach ccfile,$(ccfiles), $(eval $(call cc-defs, $(ccfile))))

но не успя със съобщение за грешка:

Makefile:19: *** commands commence before first target.  Stop.

Вместо това мога да направя това чрез:

# $(call cc-defs, ccfiles)
define cc-defs
    $1.files = $(patsubst %.cc,%.proto,$1)
endef

$(foreach ccfile,$(ccfiles), $(eval $(call cc-defs, $(ccfile))))
$(foreach ccfile,$(ccfiles), $(eval $(ccfile):$($(ccfile).files)))

Как да накарам първия метод да работи?


person Huang F. Lei    schedule 09.03.2011    source източник


Отговори (2)


Коя версия на make използвате? $(eval) се появи само в 3.80 (и работи правилно само в 3.81 IMHO).

За да отстраните грешки в makefiles, често ще трябва да се върнете към printf отстраняване на грешки. За да видите какво се случва, заменете eval с warning. Това показва какво давате да направите:

$ make --warn
Makefile:6: warning: undefined variable `ccfiles'
make: *** No targets.  Stop.

(Настрана: --warn-undefined-variables винаги е полезно. Недефинираните променливи са неподредени.)

ОК, така че трябва да дефинираме $ccfiles. Сега получаваме задействането на for цикъла:

$ make --warn ccfiles=1.cc
Makefile:6:    1.c.files = 1.cc
               1.cc:  1.c.files
make: *** No targets.  Stop.

Глоба. Не сте дали рецепти за създаване, нито цел по подразбиране. Освен това сте пропуснали някои разширения на променливи и имате допълнително място в извикването на $(for) (кофти!). Опитайте тази:

$ cat Makefile
# $(call cc-defs,ccfiles)
define cc-defs
  $1.files = $(patsubst %.cc,%.proto,$1)
  $1: $$($1.files) ; echo '[$$@]'
endef
$(foreach ccfile,$(ccfiles), $(eval $(call cc-defs,$(ccfile))))

$ make ccfiles=1.cc
make: *** No rule to make target `1.proto', needed by `1.cc'.  Stop.
person bobbogo    schedule 09.03.2011

Имайте предвид, че ако всичко, което искате да направите, е всички файлове в една променлива да зависят от (или да бъдат направени от) .proto файлове, нямате нужда от $(eval).

Правило за модел ще свърши работа (и ще работи и в по-стари версии на GNU Make):

$(ccfiles): %.cc: %.proto
        echo '[$@]'

Това наистина има страничния ефект на оплакване, когато променливата ccfiles съдържа записи без име *.cc (въпреки че все още изпълнява правилото в този случай).

$ make ccfiles=hello.cc
make: *** No rule to make target `hello.proto', needed by `hello.cc'.  Stop.
$ touch hello.proto
$ make ccfiles=hello.cc
[hello.cc]
$ make ccfiles=hello.c
Makefile:1: target `hello.c' doesn't match the target pattern
[hello.c]

Ако променливата може да съдържа много неща, но искате да добавите тази обработка само към .cc файлове, просто добавете филтър:

$(filter %.cc,$(ccfiles)): %.cc: %.proto
        echo '[$@]'

След това това води до:

$ make ccfiles=hello.cc
[hello.cc]
$ make ccfiles=hello.c
make: *** No targets.  Stop.
person Zastai    schedule 14.05.2014