我正在阅读GNU make手册,并对变量继承机制感到困惑。让我先介绍一下基础知识。
我引用了手册章 6.10来自环境的变量:
make 中的变量可以来自运行 make 的环境。 make 在启动时看到的每个环境变量都会转换为具有相同名称和值的 make 变量。
想象一下,我打开一个shell(称之为" shell 1")并定义了两个变量。然后我用两个选项启动 make ," op1"和" op2"。程序 make 本身读取一个makefile并构造一个名为" varC"的第三个变量。我们得到如下图所示的情况:
我继续阅读手册中的引文:
当 make 运行配方时,makefile中定义的变量将被放入每个shell的环境中。
这就是我现在要做的事情。执行目标的第一个配方行, make 打开一个临时shell(称之为" shell 2")。我假设所有变量" varA"," varB"和" varC"存在于该壳中,因此可以由配方线使用。虽然我不是百分百肯定。
本手册继续讲述食谱以递归方式调用 make 的情况:
默认情况下,只有来自环境或命令行的变量才会传递给递归调用。您可以使用 export 指令传递其他变量。
下一个食谱行是递归$(MAKE)
调用。顶级 make 打开一个临时shell(称之为#34; shell 3")来运行此 sub-make 实例。因为varC没有明确导出,我相信它不存在于shell 3中,也不存在于 sub-make 中。我是对的吗?
我发布了这个主题,以便从经验丰富的makefile编写者那里得到澄清。我是这个主题的新手,但我会尽我所能研究手册并在此之后开始。非常感谢所有帮助: - )
PS:如果您发布答案,请提及您的答案是否适用于Linux,Windows或两者。
答案 0 :(得分:2)
我认为你过度剖析了这段话:
当'制作'运行命令脚本,在makefile中定义变量 放在该命令的环境中。这允许你 将值传递给sub - ' make'调用。默认情况下,只有来自环境或命令行的变量才会传递给递归调用。您可以使用' export'传递其他变量的指令。
所有这些都在一起,所以只有在传入环境中或在命令行上设置的环境变量,或者在Makefile中显式地“导出” - 被放置在被调用的命令的环境中(该命令是$(MAKE)
还是其他)。
一个有趣的角落案例是传入环境和Makefile中的变量集(但未明确导出)。然后,Makefile值将覆盖传入的环境值,并且还会导出AND(因为它位于传入环境中,尽管具有不同的值)。
生成文件:
TEST = test
default:
@echo TEST="\"$$TEST\""
结果:
$ make
TEST=""
$ TEST=xx make
TEST="test"
$ make TEST=xx
TEST="xx"
答案 1 :(得分:1)
我会回答Windows,因为我这里没有Unix环境。它应该已经在GNU make
中很好地了解它的工作原理。
首先,我假设您正在讨论的环境变量具有与正在运行的shell的生命周期相关联的生命周期,因此它不是系统环境变量。
在Windows上,有两个程序可以设置变量:SET
和SETX
。可能存在更多细微之处,但为了保持简单,SET将仅为当前shell及其子进程设置变量,SETX
将设置系统环境变量。我只使用SET
,因为我不想处理系统环境变量。
我会给出一个经验性的答案。我已经完成了这个设置的测试:
\---level1
| Makefile
|
\---level2
| Makefile
|
\---level3
Makefile
level1 - Makefile
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
level2 - Makefile
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
level3 - Makefile
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文件夹中打开一个shell(Windows命令提示符)。我创建了一个变量varA
,其值为11:
SET varA=11
然后我调用第一个Makefile,它将调用第二个,它将调用第三个。
make foo
这是输出:
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
所以我们可以看到:
您可以轻松地重现此示例以执行更多测试。
请注意,您实际上可以包含另一个Makefile,因此获取其变量和规则,请参阅GNU make: Include。如果您没有密切关注所发生的事情,我建议不要使用此功能,因为如果包含的Makefile中的名称与包含的名称相同,则可以覆盖规则。
答案 2 :(得分:0)
要注意的一件事是,$(shell)的规则似乎与在配方中执行命令时的规则略有不同。
在克里斯·多德(Chris Dodd)的“有趣的极端案例”中,使用$(shell)时似乎没有传递修改。使用
的makefileIN_ENV = hello
$(info $(shell echo IN_ENV is $$IN_ENV))
all:
@echo IN_ENV is $$IN_ENV
如果您运行:
export IN_ENV=goodbye
make
您得到以下输出:
IN_ENV is goodbye
IN_ENV is hello