[GNU make]makefile中赋值符号=,:=,+=的区别详解

本文通过示例解释了Makefile中`=`和`:`两种赋值运算符的区别,强调了全局变量与局部变量在不同情境下的行为,以及如何避免递归引用的问题。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

*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是全局变量还是局部变量的话,那么默认变量为全局变量

评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值