如何将变量导出到Make的'shell'函数?

时间:2017-03-09 23:18:59

标签: gnu-make

请考虑以下事项:

$ cat a.sh
#!/bin/sh
echo in a.sh, BANANA=$BANANA
$ cat Makefile
.PHONY: foo
export BANANA = I am a banana

foo:
        $(eval F=`./a.sh`)  # BANANA is set in a.sh
        echo $F
        $(eval G=$(shell ./a.sh))  # BANANA is *not* set in a.sh
        echo $G
$ make
# BANANA is set in a.sh
echo `./a.sh`
in a.sh, BANANA=I am a banana
# BANANA is *not* set in a.sh
echo in a.sh, BANANA=
in a.sh, BANANA=

如上所示,Make的export指令告诉make在其子环境中设置变量BANANA。但该设置不适用于shell功能。它似乎适用于反引号。这是一个错误吗?如何轻松地将变量设置为shell函数的环境?

注意:

$ make --version
GNU Make 4.0
Built for x86_64-unknown-linux-gnu
Copyright (C) 1988-2013 Free Software Foundation, Inc.
License GPLv3+: GNU GPL version 3 or later <http://gnu.org/licenses/gpl.html>
This is free software: you are free to change and redistribute it.
There is NO WARRANTY, to the extent permitted by law.

1 个答案:

答案 0 :(得分:1)

首先,要清楚你的食谱的含义:

foo:
    $(eval F=`./a.sh`)  # BANANA is set in a.sh
    echo $F
    $(eval G=$(shell ./a.sh))  # BANANA is *not* set in a.sh
    echo $G

此配方包含两个(不是四个)命令:

foo:
    echo $F
    echo $G

和两个make-functions:

    $(eval F=`./a.sh`)
    $(eval G=$(shell ./a.sh))
make决定时,

将按顺序评估双线配方的范围 运行。如果您对这一点感到懊恼,请阅读this question 并回答。

另请注意,FG都是 make 变量,而不是shell变量。您 只是提到$F$G而不是$(F)$(G)6.1 Basics of Variable References的最后一段

  

美元符号后跟一个美元符号,左括号或左括号以外的字符   将该单个字符视为变量名称。因此,您可以使用'$ x'引用变量x。   但是,强烈建议不要这样做,除非是自动变量

它不适用于FFGG

因此编写makefile的正常方法是:

.PHONY: foo
export BANANA = I am a banana


foo: F=`./a.sh`
foo: G=$(shell ./a.sh)
foo:
    echo $(F)
    echo $(G)

具有完全相同的效果。

这或许澄清了echo $(F)输出之间的差异 和echo $(G)

$(shell ./a.sh)调用一个在shell中执行./a.sh的make函数 由make直接生成并返回stdout这样做。因此,对于目标foo,生成变量G将会 被定义为stdout子shell中执行./a.sh的{​​{1}}。

make不会调用任何make-function。就制造而言,它只是 一个字符串。对于目标`./a.sh`,生产变量foo将定义为F

导出的生成变量`./a.sh `未注入由生成的shell的环境中  BANANA5.7.2 Communicating Variables to a Sub-make

  

要传递或导出变量,make会将变量及其值添加到   运行食谱的每一行的环境

导出变量及其定义仅注入到shell的环境中 运行食谱。

因此$(shell ...)BANANA运行a.sh时未定义$(shell ./a.sh) 生成G的定义。但是在shell的环境中定义的 运行配方行echo $(F)$(F) = `a.sh`。那个shell(不是make)解释 `a.sh`作为子shell的反向调用,继承了定义 BANANA

要将BANANA导出到$(shell ...)的环境中,您必须这样做 它是你自己,因为它不是由make完成的:

G=$(shell export BANANA='$(BANANA)'; ./a.sh)