Advanced variable inheritance in GNU make
我正在阅读GNU make手册,并对变量继承机制感到困惑。首先让我讲一下基础知识。
我引用了手册章节6.10来自环境的变量:
Variables in make can come from the environment in which make is run. Every environment variable that make sees when it starts up is transformed into a make variable with the same name and value.
想象一下,我打开一个外壳(称为"外壳1")并定义了两个变量。然后,我用两个选项" op1"和" op2"启动make。该程序使自身读取makefile并构造第三个变量,称为" varC"。我们得到如下图所示的情况:
我继续引用手册中的一句话:
When make runs a recipe, variables defined in the makefile are placed into the environment of each shell.
这就是我现在要做的。将执行目标的第一条配方行,为此make将打开一个临时外壳(称为"外壳2")。我假设所有变量" varA"," varB"和" varC"都存在于此外壳中,因此可以由配方行使用。虽然我不确定100%。
本手册将继续介绍配方递归调用的情况:
By default, only variables that came from the environment or the command line are passed to recursive invocations. You can use the export directive to pass other variables.
下一条配方行是递归
我发布了此主题,以从经验丰富的Makefile编写者中获得澄清。我是该主题的新手,但是我正在努力研究手册,并在此之后开始使用。非常感谢所有帮助:-)
PS:如果您发布答案,请说明您的答案是否适用于Linux和/或Windows。
我认为您过分剖析了以下段落:
When 'make' runs a command script, variables defined in the makefile
are placed into the environment of that command. This allows you to
pass values to sub-'make' invocations. By default, only variables that came from the environment or the command line are passed to recursive invocations. You can use the 'export' directive to pass other variables.
所有这些结合在一起,因此仅将在传入环境或命令行中设置的环境变量,或在Makefile中显式"导出"的环境变量置于调用的命令的环境中(无论该命令是否为
一个有趣的特殊情况是在传入环境和Makefile中设置变量(但未显式导出)。然后,Makefile值将覆盖传入的环境值,并且还导出AND(因为它在传入的环境中,尽管具有不同的值)。
生成文件:
1 2 3 | TEST = test default: @echo TEST=""$$TEST"" |
结果:
1 2 3 4 5 6 | $ make TEST="" $ TEST=xx make TEST="test" $ make TEST=xx TEST="xx" |
我将仅针对Windows回答,因为我这里没有Unix环境。它应该已经很好地说明了它在
首先,我将假定您所谈论的环境变量具有与正在运行的Shell的生命周期相关联的生命周期,因此它不是系统环境变量。
在Windows上,有两个程序可以设置变量:
我会给出一个经验性的答案。我已经对此设置进行了测试:
1 2 3 4 5 6 7 8 | \---level1 | Makefile | \---level2 | Makefile | \---level3 Makefile |
级别1-Makefile
1 2 3 4 5 6 7 8 9 10 11 12 | LEVEL = LEVEL1 LEVEL1VAR = VAR1 varB = 12 export varB .PHONY: foo foo: @echo $(LEVEL) var level 1 : $(LEVEL1VAR) @echo $(LEVEL) varA is $(varA) @echo $(LEVEL) varB is $(varB) cd level2 & $(MAKE) foo |
级别2-Makefile
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 | LEVEL = LEVEL2 LEVEL2VAR = VAR2 MKID = MKID2 varC = 13 export varC .PHONY: foo foo: @echo $(LEVEL) var level 1 : $(LEVEL1VAR) @echo $(LEVEL) var level 2 : $(LEVEL2VAR) @echo $(LEVEL) varA is $(varA) @echo $(LEVEL) varB is $(varB) cd level3 & $(MAKE) foo |
3级-Makefile
1 2 3 4 5 6 7 8 9 10 11 12 | LEVEL = LEVEL3 LEVEL3VAR = VAR3 .PHONY: foo foo: @echo $(LEVEL) var level 1 : $(LEVEL1VAR) @echo $(LEVEL) var level 2 : $(LEVEL2VAR) @echo $(LEVEL) var level 3 : $(LEVEL3VAR) @echo $(LEVEL) varA is $(varA) @echo $(LEVEL) varB is $(varB) @echo $(LEVEL) varC is $(varC) |
在测试开始时,我在level1文件夹中打开一个外壳程序(Windows命令提示符)。我创建一个值为11的变量
然后,我调用第一个Makefile,后者将调用第二个,而后者将调用第三个。
这是输出:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 | LEVEL1 var level 1 : VAR1 LEVEL1 varA is 11 LEVEL1 varB is 12 cd level2 & make foo LEVEL2 var level 1 : LEVEL2 var level 2 : VAR2 LEVEL2 varA is 11 LEVEL2 varB is 12 cd level3 & make foo LEVEL3 var level 1 : LEVEL3 var level 2 : LEVEL3 var level 3 : VAR3 LEVEL3 varA is 11 LEVEL3 varB is 12 LEVEL3 varC is 13 |
这样我们可以看到:
- 可以从make的所有子调用中访问shell变量
- 可以从该Makefile的make的所有子调用中访问导出的Makefile变量。
- 无法从此Makefile的make子调用中访问未导出的Makefile变量
您可以轻松地重现此示例以执行更多测试。
请注意,您实际上可以包含另一个Makefile并因此获取其变量和规则,请参见GNU make:Include。如果您不十分注意发生的情况,我不建议使用此方法,因为如果规则在包含的Makefile中与包含在其中的规则具有相同的名称,则可以覆盖规则。
要注意的一件事是,$(shell)的规则似乎与在配方中执行命令时的规则略有不同。
在克里斯·多德(Chris Dodd)的"有趣的极端案例"中,使用$(shell)时似乎没有传递修改。用的makefile
1 2 3 4 5 | IN_ENV = hello $(info $(shell echo IN_ENV is $$IN_ENV)) all: @echo IN_ENV is $$IN_ENV |
如果您运行:
1 2 | export IN_ENV=goodbye make |
您得到以下输出:
1 2 | IN_ENV is goodbye IN_ENV is hello |