Подтвердить что ты не робот

Инициализация и экспорт переменных файла makefile

somevar := apple
export somevar
update := $(shell echo "v=$$somevar")

all:
    @echo $(update)

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

4b9b3361

Ответ 1

Проблема заключается в том, что 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"'

Ответ 2

@Beta answer содержит ключевой указатель: с 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 упоминает только, что экспортированные переменные доступны для команд рецептов.

Ответ 3

Запуск 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"), и пусть оболочка обрабатывает расширение при выполнении команды (вам все равно понадобится экспорт)

Ответ 4

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

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

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

В оболочке script, выполняемой $(shell ...), мы просто генерируем присваивание переменной формы var='$(...)', где $(...) - это некоторое выражение, которое интерполирует подходящий экранированный материал. Таким образом, 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

Run:

$ 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 передал экспортированные vars на $(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