Раннее расширение переменных в рецептах - PullRequest
0 голосов
/ 21 января 2019

Я знаю о различии между двумя типами переменных в 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?

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

Ответы [ 2 ]

0 голосов
/ 05 февраля 2019

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

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

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

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

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

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

  • make расширяется $(eval ${rule})
    • Сначала расширяется ${rule}
      • $$ расширяется до $
      • Все вхождения ${FOO} заменены на Bar
      • , оставив нам этот текст:PHONY: BarBar: @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]

0 голосов
/ 22 января 2019

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

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, как и все специальные цели, начинается с .)

...