6.1变量中的变量
在定义变量的值时,我们可以使用其他变量来构造变量的值,在Makefile中有两种定义变量的值。
先看第一种方式,也就是简单的使用“=”号,在“=”左侧是变量,右侧是变量的值,右侧变量的值可以定义在
文件的任何一处,也就是说,右侧中的变量不一定非要是已定义好的值,其也可以使用后面定义的值。如:
foo=$(bar)
bar=$(ugh)
ugh=Huh?
all:
echo$(foo)
此时输出的值为“Huh?”可见,变量是可以使用后面的变量来定义的。
这个方法的好处是可以把变量的真实值推到后面来定义,但是不好的地方是当被递归定义时会反复调用例如:
A=$(B)
B=$(A)
这会让 make 陷入无限的变量展开过程中去。
第二种方法是使用“:=”,操作符这种方法,前面的变量不能使用后面的变量,只能使用前面已定义好了的变量。
x:=foo
y:=$(x)bar
x:=later
其等价于:
y:=foobar
x:=later
值得一提的是,这种方法,前面的变量不能使用后面的变量,只能使用前面已定义好了的变量。如果是这样:
y:=$(x)bar
x:=foo
那么,y 的值是“bar”,而不是“foobar”。
当需要定义一个空格时
nullstring:=
space:=$(nullstring)#end of the line
采用“#”注释符来表示变量定义的终止,这样,我们可以定义出其值是一个空格的变量。
注意这个特性以避免自己所定义的变量与想要的不符合。
还有一个比较有用的操作符是“?=”
FOO?=bar
其含义是,如果 FOO 没有被定义过,那么变量 FOO 的值就是“bar”,如果 FOO 先前被定义过,那么这条语将什么也不做
6.2变量的高级用法
两种高级变量使用方法,一种是变量值的替换,适用于类似变量的重命名
格式是“$(var:a=b)”或是“${var:a=b}”,其意思是,把变量“var”中所有以“a”字串“结尾”的“a”替换成“b”字串。这里的“结尾”意思是“空格”或是“结束符”,示例如下
foo:=a.o b.o c.o
bar:=$(foo:.o=.c)
先定义了一个“$(foo)”变量,而第二行的意思是把“$(foo)”中所有以“.o”字串“结尾”全部替换成“.c”,所以我们的“$(bar)”的值就是“a.c b.c c.c”。
第二种替换模式是是以“静态模式定义的”如:
foo:=a.o b.o c.o
bar:=$(foo:%.o=%.c)
这依赖于被替换字串中的有相同的模式,模式中必须包含一个“%”字符,效果与前一种相同。
第二种是将变量的值当成变量
x=y
y=z
a:=$($(x))
在这个例子中,$(x)的值是“y”,所以$($(x))就是$(y),于是$(a)的值就是“z”。(注意,是“x=y”,而不是“x=$(y)”),类似于c语言多重指针的解引用。
在这种方式中,或要可以使用多个变量来组成一个变量的名字,然后再取其值:
first_second=Hello
a=first
b=second
all=$($a_$b)
$(all)的值就是“Hello”。
当两种技术结合在一起的时候
a_objects:=a.o b.o c.o
1_objects:=1.o 2.o 3.o
sources:=$($(a1)_objects:.o=.c)
其中变量$(a1)值待定,如果$(a1)的值是“a”的话,那么,$(sources)的值就是“a.c b.c c.c”;如果$(a1)的值是“1”,那么$(sources)的值是“1.c 2.c 3.c”。
这种技术和“函数”与“条件语句”一同使用的例子
ifdef do_sort
func:=sort
else
func:=strip
endif
bar:=a d b g q c
foo:=$($(func) $(bar))
如果定义了“do_sort”,那么:foo:=$(sort a d b g q c),于是$(foo)的值就是“a b d g q”,而如果没有定义“do_sort”,那么:foo:=$(sort a d b g q c),调用的就是 strip 函数。
关于sort函数的用法见https://blog.youkuaiyun.com/zhoudengqing/article/details/41778007
函数的用法见striphttps://www.jianshu.com/p/b587652bcb44
6.3追加变量值
可以使用“+=”操作符给变量追加值,如:
objects=main.o foo.o bar.o utils.o
objects+=another.o
$(objects)值变成:“main.o foo.o bar.o utils.o another.o”(another.o 被追加进去了)
如果变量之前没有定义过,那么,“+=”会自动变成“=”,如果前面有变量定义,那么“+=”会继承于前次操作的赋值符。如果前一次的是“:=”,那么“+=”会以“:=”作为其赋值符,如
variable:=value
variable+=more
等价于:
variable:=value
variable:=$(variable) more
6.4 override指示符
参考了https://blog.youkuaiyun.com/wh_19910525/article/details/41279909博客的内容,比较详细,这里拿过来总结一下:
如果有变量是通常 make 的命令行参数设置的,那么 Makefile 中对这个变量的赋值会被忽略。如果你想在Makefile 中设置这类参数的值不被命令行参数覆盖,那么,你可以使用“override”指示符。其语法是:
override <variable>=<value>
override <variable>:=<value>
当然,你还可以追加:
override <variable>+=<moretext>
对于追加方式需要说明的是:变量在定义时使用了“override”,则后续对它值进行追加时,也需要使用带有“override”指示符的追加方式。否则对此变量值的追加不会生效。
override指示符的作用是用于实现makefile增加或者修改命令行参数的一种机制。我们可能会有这样的需求;可以通过命令行来指定一些附加的编译参数,对一些通用的参数或者必需的编译参数在Makefile中指定,而在命令行中指定一些特殊的参数。对于这种需求,我们就需要使用指示符“override”来实现。
例如:无论命令行指定那些编译参数,编译时必须打开“-g”选项,那么在Makefile中编译选项“CFLAGS”应该这样定义:
override CFLAGS += -g
这样,在执行make时无论在命令行中指定了那些编译选项(“指定CFLAGS”的值),编译时“-g”参数始终存在。
最后我们来看一个例子:
# sample Makefile
EXEF = foo
override CFLAGS += -Wall –g
.PHONY : all debug test
all : $(EXEF)
foo : foo.c
………..
………..
$(EXEF) : debug.h
$(CC) $(CFLAGS) $(addsuffix .c,$@) –o $@
debug :
@echo ”CFLAGS = $(CFLAGS)”
执行:make CFLAGS=-O2 将显式编译“foo”的过程是“cc –O2 –Wall –g foo.c –o foo”。执行“make CFLAGS=-O2 debug”可以查看到变量“CFLAGS”的值为“–O2 –Wall –g”。