*1 = 与 :=
- 都是赋值运算符
- 都可以重定义
- =是全局范围赋值
- :=是局部范围赋值
- 使用=对一个变量赋值后,会将变量转化为全局范围内赋值的变量,此处我们称为“全局赋值变量”
- 使用:=对一个变量赋值后,会将变量转化为局部范围内赋值的变量,此处我们称为“局部赋值变量”
- 对同一变量交替使用两者并不冲突,每次用=或:=赋值时会在此次操作时立刻转变变量的类型
何为局部赋值变量,何为全局赋值变量?全局赋值用的是整个makefile里的最终结果替换表达式右端项,而局部赋值,用的是这一步赋值前的临时结果替换表达式右端项。看了下面的一堆例子或许就清晰了:
示例1
varA = a
varB = $(varA)
varA = aa
debug :
@echo $(varB)
终端输入make debug,此时会输出aa而非a,原因在于,B使用的是=,意味着表达式右端引用的任何变量,makefile文件在确定值的时候会寻找其最终被确定的值。此处,varB使用了varA的值,由于是=赋值,故varB=$(varA)时会找varA的最终结果(这与varA是全局的还是局部的无关)
示例2
varA = a
varB := $(varA)
varA = aa
debug :
@echo $(varB)
make debug后,会输出a。因为varB赋值会寻找这条语句前最后确定的A的值
示例3
varB := $(varA)
varA = aa
debug :
@echo $(varB)
make debug后,会输出空字符串。因为varB赋值前变量varA不存在,或者说没有值。
示例4
varA = a
varB = $(varA)
varA = $(varB)
debug :
@echo $(varA)
@echo $(varB)
make debug,会立刻报错:“*** 递归变量“varA”(最终将会)引用自身。 停止。”
分析一下,这里由于varA varB都是全局赋值,于是varB会去寻找varA的最终值,而varA的最终值又是varB的最终值,两者套娃,无限找对方的值,本质上变成,varA = $(varA)
因此这种情况是要避免的,因此最好还是用:=,改成如下的:
示例5
varA = a
varB := $(varA)
varA = $(varB)
debug :
@echo $(varA)
@echo $(varB)
此时就会正常输出两行a
还有一些例子:
示例6
varA = $(varB)
varB := $(varA)
debug :
@echo $(varA)
@echo $(varB)
此时会输出两个空行。为何此处没有导致自引用?因为varB是局部变量,它的值赋为varA的值,然而varA的值是varB的最终值,于是化为varA:=$(varA),这相当于,在varA取了在varA之前的值,,然而这之前varA未被定义,未定义的值是空值,于是varA被赋了空值。从而varB也被赋了空值。
我们可以看下面这个例子:
示例7
varA := $(varA)
debug :
@echo $(varA)
会输出一个空行
我们再考虑如下的例子
示例8
varA = $(varB)
varB := $(varA)
varB += bbb
debug :
@echo $(varA)
@echo $(varB)
结果是,varB = bbb, varA = bbb
而非,varB = bbb bbb,varA = bbb
分析如下:
第二行处
varB := $(varA) := ( ( ((varB)) := $([undefined]) :=
此时varB为空值,于是可以解释这一结果。关于+=见下一部分
2 累加 +=
- var += xxx
- 本质上是 var = $(var) xxx //注意,中间有一个空格
- 或是 var := $(var) xxx
如何确定+=用的是 = 还是 :=呢?取决于这个变量是全局赋值变量还是局部赋值变量
- 如果这个变量是全局赋值变量,那么用的是 =
- 如果是局部赋值变量,那么用的是 :=
示例9
x = a
y = b
x += $(y)
y = c
debug :
@echo $(x)
此时,会输出a c而非a b
因为在+=号这一步之前,x的性质是全局赋值的
示例10
x := a
y = b
x += $(y)
y = c
debug :
@echo $(x)
此时,会输出a b而非a c
因为在+=号这一步之前,x的性质是局部赋值的
示例11
x := a
x = a
y = b
x += $(y)
y = c
debug :
@echo $(x)
此时,会输出a c而非a b
因为在+=号这一步之前的最后一次修改,将x的性质改为全局赋值的了
示例12
x := a
y = b
x += $(y) //这一步后x = a b,x在这一步是全局的还是局部的取决于之前的操作而非之后的操作
x = a
y = c
debug :
@echo $(x)
不过最终会输出a,因为后来对x重新赋值了。
示例13
y = b
x += $(y)
y = c
debug :
@echo $(x)
会输出c而非b,这意味着,如果在x使用+=前没有对x进行过赋值操作,没有显式地确定x是全局变量还是局部变量的话,那么默认变量为全局变量