GNU中的高级变量继承使

时间:2016-08-19 10:31:07

标签: makefile gnu-make

我正在阅读GNU make手册,并对变量继承机制感到困惑。让我先介绍一下基础知识。

我引用了手册章 6.10来自环境的变量:

  

make 中的变量可以来自运行 make 的环境。 make 在启动时看到的每个环境变量都会转换为具有相同名称和值的 make 变量。

想象一下,我打开一个shell(称之为" shell 1")并定义了两个变量。然后我用两个选项启动 make ," op1"和" op2"。程序 make 本身读取一个makefile并构造一个名为" varC"的第三个变量。我们得到如下图所示的情况:

enter image description here

我继续阅读手册中的引文:

  

make 运行配方时,makefile中定义的变量将被放入每个shell的环境中。

这就是我现在要做的事情。执行目标的第一个配方行, make 打开一个临时shell(称之为" shell 2")。我假设所有变量" varA"," varB"和" varC"存在于该壳中,因此可以由配方线使用。虽然我不是百分百肯定。

enter image description here

本手册继续讲述食谱以递归方式调用 make 的情况:

  

默认情况下,只有来自环境或命令行的变量才会传递给递归调用。您可以使用 export 指令传递其他变量。

下一个食谱行是递归$(MAKE)调用。顶级 make 打开一个临时shell(称之为#34; shell 3")来运行此 sub-make 实例。因为varC没有明确导出,我相信它不存在于shell 3中,也不存在于 sub-make 中。我是对的吗?

enter image description here

我发布了这个主题,以便从经验丰富的makefile编写者那里得到澄清。我是这个主题的新手,但我会尽我所能研究手册并在此之后开始。非常感谢所有帮助: - )

PS:如果您发布答案,请提及您的答案是否适用于Linux,Windows或两者。

3 个答案:

答案 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上,有两个程序可以设置变量:SETSETX。可能存在更多细微之处,但为了保持简单,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

所以我们可以看到:

  • 可以从make
  • 的所有子调用中访问shell变量
  • 可以从Makefile的make的所有子调用中访问导出的Makefile变量
  • 无法从make Makefile的子调用中访问未导出的Makefile变量

您可以轻松地重现此示例以执行更多测试。

请注意,您实际上可以包含另一个Makefile,因此获取其变量和规则,请参阅GNU make: Include。如果您没有密切关注所发生的事情,我建议不要使用此功能,因为如果包含的Makefile中的名称与包含的名称相同,则可以覆盖规则。

答案 2 :(得分:0)

要注意的一件事是,$(shell)的规则似乎与在配方中执行命令时的规则略有不同。

在克里斯·多德(Chris Dodd)的“有趣的极端案例”中,使用$(shell)时似乎没有传递修改。使用

的makefile
IN_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