Раннее расширение переменных в рецептах
Я знаю о различии двух типов переменных в 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]