Вы можете написать красивый функциональный код (каламбур), используя $(eval …)
.Вы можете написать замыкания и решить, что будет расширено, когда.
Рассмотрите эту переменную:
define rule =
PHONY: ${FOO}
${FOO}:
@echo $$@ ${FOO}
endef
Ничего странного здесь нет.Но посмотрите, что произойдет, когда мы передадим его в eval :
FOO := Bar
$(eval ${rule})
Нам бы лучше взглянуть на эту последнюю строку подробнее.
- make расширяется
$(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]