Makefile变量初始化和导出

Pab*_*blo 31 variables export makefile

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

all:
    @echo $(update)
Run Code Online (Sandbox Code Playgroud)

我希望苹果作为命令的输出,但它是空的,这使我认为出口和:=变量扩展发生在不同的阶段.怎么克服这个?

Bet*_*eta 33

问题是export将变量导出到命令使用的子shell; 它不适用于其他作业的扩展.所以不要试图从规则之外的环境中获取它.

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"'
Run Code Online (Sandbox Code Playgroud)


mkl*_*nt0 16

@ Beta的答案包含关键指针:使用GNU make,标记的变量export仅可用于[为命令启动的shell] 命令(作为规则的一部分的命令),遗憾的是不能调用 $(shell ...)(它们只能看到make自己看到的环境)它被推出了).

但是有一种解决方法:显式将导出的变量作为环境变量传递给shell函数:

update := $(shell somevar='$(somevar)' perl -e 'print "$$ENV{somevar}"')
Run Code Online (Sandbox Code Playgroud)

通过预先添加shell命令<var>=<val>,该定义将作为环境变量添加到命令所看到的环境中 - 这是一个通用的shell功能.

警告:@Kaz在评论中指出,如果$(somevar)包含某些字符,此方法会出错,因为变量扩展是逐字的(无转义),这可能会破坏生成的shell命令,并建议以下变体也适用于嵌入式'实例(将输入值分为单引号子串,引用'拼接in):

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

这应该适用于除多行之外的所有值(这种情况很少见;我所知道的多行值没有解决方法).

旁注,文字$字符.in值必须表示为$$,否则make将把它们解释为对自己变量的引用.

请注意,我故意不选择OP的原始语句,update := $(shell echo "v=$$somevar")用于演示,因为它包含一个混淆问题的陷阱:由于shell如何评估命令行,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仅提到使导出变量可用于配方命令.


Sco*_*les 10

运行makefile

foo:=apple
export foo
all:
        @echo ">"$(shell echo "$$foo")
        @echo ">""$$foo"
Run Code Online (Sandbox Code Playgroud)

给我(在环境中未定义foo)

$ make
>
>apple

$ make foo=bar
>
>apple

$ export foo=bar; make
>bar
>apple

$ export foo=bar; make foo=bar
>bar
>bar
Run Code Online (Sandbox Code Playgroud)

尝试使用带引号的表单(update := "v=$$somevar")并在运行命令时让shell处理扩展(您仍然需要导出)

  • +1表示变化;简而言之:(a) `$(shell ...)` 只能看到 `make` 启动时已经存在于自己的环境中的变量;(b) 在 `make` 命令行上定义变量会覆盖 makefile 中同名的定义。 (2认同)