一、简述
1、"="赋值,这种形式是以递归的形式展开变量,及被赋值的变量只有在被引用(使用)时,才会展开,及延迟展开(不常用)
2、":="赋值,这种形式是直接展开式赋值。
二、举例
例子1:
foo = $(bar)
bar = $(ugh)
ugh = Huh?
all:;echo $(foo)
例子来源于GnuMake
上述例子执行结果为(其中all:;echo $(foo)等价于 将分号去掉,echo语句换行并以tab键开头)
echo Huh?
Huh?
如果将 foo = $(bar)替换成 foo:=$(bar)呢:
foo := $(bar)
bar = $(ugh)
ugh = Huh?
all:;echo $(foo)
执行结果如下:
echo
可以看到foo变量为空,这就印证了简述中的定义,foo直接展开式赋值时,bar变量为空(还未赋值),所以foo也为空,foo递归展开赋值时,在调用echo 语句时才被展开,所以此时bar的值为Hub?,所以foo的值也是Hub?
例子2:
网上有一种说法: "=" make会将整个makefile展开后,再决定变量的值,":="表示变量的值决定于它在makefile中的位置,而不是整个makefile展开式的最终结果
那么这句话对吗,我个人认为这种描述是不精确的,会给人带来误区,“:=” 和"="的区别还是按照例子1中的测试结果描述,我们将上例做如下添加:
foo := $(bar)
bar = $(ugh)
ugh = Huh?
all:
echo $(foo)
foo := hello
如果按照上述网上的说法,那么你很可能认为 foo仍然为空,但实际执行结果为:
echo hello
hello
实际上一般make执行确定的目标前,会将所有的变量赋值全部读取,解析,也就是调用all目标之前,foo:=hello 已经被读取了,并且已经生效了,所以,echo $(foo)的结果会是hello,那上述网络描述是什么意思呢?其实他的本来的意思是,如果一个变量foo只在一个地方被赋值的时候 用"="和":="被赋值的区别是,如果赋值的内容中有变量,"="会等Makefile全部展开后,所有的变量值再来为foo变量赋值,而":="不会等Makefile全部展开,而是foo变量之前所有展开的变量的值来为foo进行赋值,如果foo:=$(bar),其中bar变量在foo变量之前还没有展开,则bar变量就按空处理,将空赋值为foo。所以上述网络说法可以在这种情况下可以套用。
而我们是在一个Makefile中的多个地方为同一变量赋值,所以会产生歧义,如果Makefile中在多个地方对同一变量进行赋值,无论用“=”还是":="都是按照Makefile展开的顺序,最后为变量赋值的地方是最终生效的赋值语句。
如果将上述例子中所有的 ":=" 变成 "=" 那么执行结果也是毫无疑义的,如下:
foo = $(bar)
bar = $(ugh)
ugh = Huh?
all:
echo $(foo)
foo = hello
执行结果:
echo hello
hello
另外,其实并不推荐 := 和= 在变量赋值中交替混合使用,其实 =并不常用。