Раннее расширение переменных в рецептах

Я знаю о различии двух типов переменных в GNU Make.

В настоящее время я пишу систему сборки, в которой определенные переменные определены в подкаталогах (например, VERSION). Чтобы упростить жизнь авторам подкаталогов, я не хочу заставлять их делать свои переменные глобально уникальными. Я также хотел бы избежать рекурсивного создания.

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

FOO := Bar
PHONY: $(FOO)
$(FOO):
    @echo $(FOO)

FOO := Definitely not Bar

PHONY: test2
test2: Bar
    @echo $(FOO)

Мне понадобится вывод make test2 быть

Bar
Definitely not Bar

Конечно, я мог бы использовать временную переменную для принудительного расширения FOO в первом правиле, но затем мне нужен способ надежного определения новой временной переменной. Есть ли способ расширить цель, например, используя eval?

Изменить: Сделано любопытное расширение FOO более ясно в коде примера.

2 ответа

Выглядит так, как будто вы просто хотите целевые переменные, например

Makefile

.PHONY: Bar test2

Bar: FOO := Bar
Bar:
    @echo $(FOO)

test2: FOO := Definitely not Bar
test2: Bar
    @echo $(FOO)

который работает как:

$ make test2
Bar
Definitely not Bar

(Обратите внимание, что .PHONYКак и все специальные цели, начинается с .)

Вы можете написать красивый функциональный код (каламбур), используя $(eval …), Вы можете написать замыкания и решить, что будет расширено.

Рассмотрим эту переменную:

define rule =
PHONY: ${FOO}
${FOO}:
        @echo $$@ ${FOO}
endef

Ничего странного здесь нет. Но посмотрите, что произойдет, когда мы передадим его в eval:

FOO := Bar
$(eval ${rule})

Нам бы лучше взглянуть на эту последнюю строку подробно.

  • сделать расширяется $(eval ${rule})
    • Сначала это расширяется ${rule}
      • $$ расширяется до $
      • Все случаи ${FOO} заменены на Bar
      • оставив нас с этим текстом:
        PHONY: Bar
        Bar:
        @echo $@ Bar
        Можете ли вы увидеть, как текущее значение ${FOO} был запечен в рецепт?
    • Теперь блок синтаксиса make передается $(eval)
      • Make создает новое правило как побочный эффект eval
    • Расширение eval, хотя и пусто.

Ницца.

FOO := Dead
$(eval ${rule})

FOO := Beef
$(eval ${rule})

Вы не очень далеки от отказа от глобальных переменных в пользу локальных параметров:

$(call makerule,Dead)
$(call makerule,Beef)

Должно быть хорошо, не так ли?

[AFAICR eval не очень хорошо работал в make 3.81, поэтому используйте как минимум версию 3.82]

Другие вопросы по тегам