Инициализация и экспорт переменных Makefile - PullRequest
30 голосов
/ 15 мая 2010
somevar := apple
export somevar
update := $(shell echo "v=$$somevar")

all:
    @echo $(update)

Я надеялся на вывод команды, но он пуст, что заставляет меня думать об экспорте и расширении переменных := на разных этапах. как это побороть?

Ответы [ 4 ]

32 голосов
/ 15 мая 2010

Проблема в том, что export экспортирует переменную в подоболочки, используемые командами; он не доступен для расширения в других назначениях. Так что не пытайтесь получить это из среды вне правила.

somevar := apple
export somevar

update1 := $(shell perl -e 'print "method 1 $$ENV{somevar}\n"')
# Make runs the shell command, the shell does not know somevar, so update1 is "method 1 ".

update2 := perl -e 'print "method 2 $$ENV{somevar}\n"'
# Now update2 is perl -e 'print "method 2 $$ENV{somevar}\n"'

# Lest we forget:
update3 := method 3 $(somevar)

all:
    echo $(update1)
    $(update2)
    echo $(update3)
    perl -e 'print method 4 "$$ENV{somevar}\n"'
14 голосов
/ 23 октября 2014

@ Бета-ответ содержит критический указатель: с GNU make, переменные, отмеченные export, доступны только для [оболочек, запущенных для] команд рецепта (команды, являющиеся частью правил), к сожалению , а не вызовы $(shell ...) (они видят только среду, которую make видел сам при запуске).

Существует обходной путь , однако: явно передает экспортированную переменную как переменную среды в функцию shell:

update := $(shell somevar='$(somevar)' perl -e 'print "$$ENV{somevar}"')

За счет добавления команды оболочки к <var>=<val> это определение добавляется в качестве переменной среды в среду, которую видит команда - это общая функция оболочки.

Caveat : @Kaz указывает в комментарии, что этот метод ведет себя неправильно, если $(somevar) содержит определенные символы., Потому что расширение переменной равно дословно (без экранирования), что может разбить получившуюся команду оболочки и предлагает следующий вариант , чтобы также работать со встроенными ' экземплярами (разбивает входное значение на подстроки с одинарными кавычками, с кавычками ':)

update := $(shell somevar='$(subst ','\'',$(somevar))' perl -e 'print "$$ENV{somevar}"')

Это должно работать со всеми значениями, за исключением многострочных (редких; обходного пути для многострочных значений, о которых я знаю).

На боковой ноте буквально $ символов. значения должны быть представлены как $$, в противном случае make будет интерпретировать их как ссылки на свои собственные переменные.

Обратите внимание, что я специально НЕ выбрал для демонстрации оператор оригинала OP, update := $(shell echo "v=$$somevar"), потому что он содержит ловушку, которая запутывает проблему: из-за того, как оболочка оценивает командную строку, somevar=apple echo v=$somevar делает НЕ оценивается как v=apple, поскольку ссылка $somevar раскрывается до того, как somevar=apple вступит в силу. Чтобы достичь желаемого эффекта в этом случае, вы должны будете использовать 2 операторов: update := $(shell export somevar="$(somevar)"; echo "v=$$somevar")


Что касается дебатов об ошибках и функциях:

Хотя можно утверждать, что функция shell должна видеть ту же среду, что и команды рецепта, документация не дает такого обещания - см. http://www.gnu.org/software/make/manual/make.html#Shell-Function. И наоборот, http://www.gnu.org/software/make/manual/make.html#Variables_002fRecursion упоминается только о том, что экспортируемые переменные доступны для рецепт команд.

10 голосов
/ 15 мая 2010

Запуск make-файла

foo:=apple
export foo
all:
        @echo ">"$(shell echo "$$foo")
        @echo ">""$$foo"

дает мне (с foo undefined в среде)

$ make
>
>apple

$ make foo=bar
>
>apple

$ export foo=bar; make
>bar
>apple

$ export foo=bar; make foo=bar
>bar
>bar

Попробуйте использовать форму в кавычках (update := "v=$$somevar") и разрешите оболочке обрабатывать расширение при выполнении команды (вам все равно понадобится экспорт)

1 голос
/ 17 января 2015

Хотя export не очень хорошо играет с $(shell ...), существует простой обходной путь. Мы можем передать данные в сценарий оболочки через командную строку.

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

ab'cd -> 'ab'\''cd'

В сценарии оболочки, выполняемом $(shell ...), мы просто генерируем присвоение переменной в форме var='$(...)', где $(...) - это некоторое выражение make, которое интерполирует подходящим образом экранированный материал. Таким образом, Makefile:

somevar := apple with 'quoted' "stuff" and dollar $$signs

shell_escape = $(subst ','\'',$(1))

update := $(shell v='$(call shell_escape,$(somevar))'; echo $$v > file.txt)

.phony: all

all:
    cat file.txt

Пример прогона:

$ make
cat file.txt
apple with 'quoted' "stuff" and dollar $signs

Если мы хотим передать переменную окружения команде, мы можем сделать это, используя синтаксис оболочки VAR0=val0 VAR1=val1 ... VARn=valn command arg .... Это может быть проиллюстрировано некоторыми незначительными изменениями в Makefile:

somevar := apple with 'quoted' "stuff" and dollar $$signs

shell_escape = $(subst ','\'',$(1))

update := $(shell somevar='$(call shell_escape,$(somevar))' env > file.txt)

.phony: all

all:
        grep somevar file.txt

Пробег:

$ make
grep somevar file.txt
somevar=apple with 'quoted' "stuff" and dollar $signs

file.txt содержит дамп переменных среды, где мы можем увидеть somevar. Если бы export в GNU Make поступил правильно, мы могли бы просто сделать:

export somevar
update := $(shell env > file.txt)

но конечный результат тот же.

Поскольку конечный результат, который вам нужен, равен echo $(update), вы все равно бы shell_escape, даже если GNU Make передал экспортированные переменные в $(shell ...). То есть посмотрите на еще один Makefile:

somevar := apple with 'quoted' "stuff" and dollar $$signs

shell_escape = $(subst ','\'',$(1))

update := $(shell v='$(call shell_escape,$(somevar))'; echo $$v)

.phony: all

all:
    @echo '$(call shell_escape,$(update))'
    @echo $(update)

Выход:

apple with 'quoted' "stuff" and dollar $signs
apple with quoted stuff and dollar
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...