之前面试被问到Makefile中":="和"="的区别,真没说上来,只是通过读一些现成的Makefile猜测大概意思——”反正就是赋值呗~“
其实不光这两个, "=" ":=" "?=" "+="这几个都是常用赋值运算符,那么他们有什么区别呢?
做个试验,新建一个make文件,文件名自拟——[makefilename](默认Makefile),结构有点像switch加case:
ifdef DEFINE_VALUE
VALUE = “Hello World!”
else
endif
ifeq ($(OPT),define)
VALUE ?= “Hello World! First!”
endif
ifeq ($(OPT),add)
VALUE += “Hu!”
endif
ifeq ($(OPT),recover)
VALUE := “Hello World! Again!”
endif
all:
@echo $(VALUE)
这是参考定义:
= 是最基本的赋值
:= 是覆盖之前的值
?= 是如果没有被赋值过就赋予等号后面的值
+= 是添加等号后面的值
下面进行测试:
首先尝试"?=",如果他表示未赋值则赋值,设立如下对照组
make -f makefilename DEFINE_VALUE=true OPT=define
make -f makefilename DEFINE_VALUE=false OPT=define
make -f makefilename OPT=define
通过对照组的结果得知,所谓未赋值,并不是不为true,false一样算赋值,所以需要空掉,这时候"?="就会赋值。
现在尝试"+=",比较容易理解——在后边追加,和C语言字符串操作差不多,输入如下命令:
make -f makefilename DEFINE_VALUE=true OPT=add
make -f makefilename DEFINE_VALUE=false OPT=add
make -f makefilename OPT=define
没什么需要解释的,前两个结果一样,最后一个相当于给空“字符串”加了个尾巴——只有尾巴存在。
接下来是我被问到的,也是最容易碰到的问题,":="和"=":
make -f makefilename DEFINE_VALUE=false OPT=recover
make -f makefilename OPT=recover
结果一样~
如果我在ifeq ($(OPT),recover)前边加个echo或者根本不加OPT赋值,很容易就发现区别,证明":="是覆盖初始赋值。
其实"="也能赋值,此处并不能很好的表现":="的特性,而相应的比较有代表性的是这种情况:
A := first
B := $(A) add
A := final
all:
@echo $(B)
A = first
B = $(A) add
A = final
all:
@echo $(B)
透过结果可以看出,使用"="时,B中A的值要看最后一次定义"final",而使用":="时,B中A的值要只取决于之前的"first"。也就是说有":="的更像C语言有先后顺序,注重过程和顺序;而"="则更像我们体验到的依赖关系,是个大展开,注重结果。
PS:ifeq和后边的括号之间有空格,命令tab开头,注释#开头,依赖关系(或者判断语句?)顶格
小疑惑:
all:代表什么?代表目标all什么都不依赖就直接执行,但是产生了all文件么?也不产生!类似于#make clean是通过clean:标识实现的,同样也可以#make all(反正默认到最后
也会执行),它和#make的区别绝不是一个跳过去直接执行all,一个不执行,那样的话忽略了前边的赋值过程,#make all结果都出不来(结果是能出来)——或者不严谨的说,至少这句依赖的语句或者叫赋值过程,是都要执行的。
具体含义需深挖,但不太属于本次探讨了,本次主要关系各赋值语句区别。
做个例子吧,至少能探知使用时的规律:
#test
a=1
b=2
c=$(a)+$(b)
a:
@echo $(a)
b:
@echo $(b)
#让a总共有3次赋值(包括":=")。另加一次屏显,可以看到谁被执行了而谁被忽略了
#b=100
@echo "test"
#a=10
c:
@echo $(c)
#a:=20
输入命令:
#make a
#make b
#make c
#make a b c
#make
测试结果:
首先是执行规律,凭空的加@echo不好用,直接归类到"b:"下了,而如果试图使用b=100分割这两个echo,后边的直接无效,就是说任何命令还是要依托于类似"flag:"的形式。
除此,基本还是按选项来的,你不加参数选项"a"、"b"、"c"它自己不会执行(其实通过#make可以看出,它默认执行了a选项,也就是第一个标签,假如只有一个"all:",当然就自
动执行它了),也就是相当于#make c直接跳到"c:"标识去执行。但是依赖的参数,比如a,都会找到并且使用。
是相当于#make c直接跳到"c:"标识去执行。但是依赖的参数,比如a,都会找到并且使用
首先,凭空的@echo “test"不好用,直接归类到"b:"下了,而如果试图使用b=100分割这两个echo,后边的直接无效,就是说任何命令还是要依托于类似"flag:"的形式。
除此,基本还是按选项来的,你不加参数它自己不会执行,也就是相当于#make c直接跳到"c:"标识去执行。但是依赖的参数,比如a,都会找到并且使用
如果让a多加两次赋值(注释"#"去掉),会发现最后的c值受影响了~而且是按"a:=20"算的!好像推翻了之前的认知了??????
因为在最后加了个“按顺序执行的”冒号等于"a:=20",如果真按顺序的话,这次赋值在最后,应该不生效。哪出了错误???
其实仔细分辨,会发现研究的对象错了。
对比两例发现:
之前是B := $(A) add,本次是c=$(a)+$(b)
可以发现:
其实关键点不应该是"a:=20",是c=$(a)+$(b)
修改为:
c:=$(a)+$(b)
之后可以发现
#make c
的结果不再受后边a值变化的影响了,也就是说,在遇到关键点":="时发生一次判定,研究的目标应该是被赋值的c,而不是变量a。
关于Makefile的各种赋值符号和标签执行规律,布布扣,bubuko.com
关于Makefile的各种赋值符号和标签执行规律
原文:http://blog.csdn.net/huqinwei987/article/details/23035583