―$$‖来表示。
变量可以使用在许多地方,如规则中的―目标‖、―依赖‖、―命令‖以及新的变量中。 先看一个例子:
objects = program.o foo.o utils.o program : $(objects) cc -o program $(objects)
$(objects) : defs.h
变量会在使用它的地方精确地展开,就像C/C++中的宏一样,例如: foo = c
prog.o : prog.$(foo)
$(foo)$(foo) -$(foo) prog.$(foo)
展开后得到:
prog.o : prog.c cc -c prog.c
当然,千万不要在你的Makefile中这样干,这里只是举个例子来表明Makefile中的变量在
使用处展开的真实样子。可见其就是一个―替代‖的原理。
另外,给变量加上括号完全是为了更加安全地使用这个变量,在上面的例子中,如果你不
想给变量加上括号,那也可以,但我还是强烈建议你给变量加上括号。
二、变量中的变量
在定义变量的值时,我们可以使用其它变量来构造变量的值,在Makefile中有两种方式来
在用变量定义变量的值。
先看第一种方式,也就是简单的使用―=‖号,在―=‖左侧是变量,右侧是变量的值,右
侧变量的值可以定义在文件的任何一处,也就是说,右侧中的变量不一定非要是已定义好
的值,其也可以使用后面定义的值。如:
foo = $(bar) bar = $(ugh) ugh = Huh? all:
echo $(foo)
我们执行―make all‖将会打出变量$(foo)的值是―Huh?‖( $(foo)的值是$(bar),$(b
ar)的值是$(ugh),$(ugh)的值是―Huh?‖)可见,变量是可以使用后面的变量来定义的。
这个功能有好的地方,也有不好的地方,好的地方是,我们可以把变量的真实值推到后面 来定义,如:
CFLAGS = $(include_dirs) -O include_dirs = -Ifoo -Ibar
当―CFLAGS‖在命令中被展开时,会是―-Ifoo -Ibar -O‖。但这种形式也有不好的地方
,那就是递归定义,如:
CFLAGS = $(CFLAGS) -O 或:
A = $(B) B = $(A)
这会让make陷入无限的变量展开过程中去,当然,我们的make是有能力检测这样的定义,
并会报错。还有就是如果在变量中使用函数,那么,这种方式会让我们的make运行时非常
慢,更糟糕的是,他会使用得两个make的函数―wildcard‖和―shell‖发生不可预知的错
误。因为你不会知道这两个函数会被调用多少次。
为了避免上面的这种方法,我们可以使用make中的另一种用变量来定义变量的方法。这种
方法使用的是―:=‖操作符,如:
x := foo
y := $(x) bar x := later
其等价于:
y := foo bar x := later
值得一提的是,这种方法,前面的变量不能使用后面的变量,只能使用前面已定义好了的
变量。如果是这样:
y := $(x) bar x := foo
那么,y的值是―bar‖,而不是―foo bar‖。
上面都是一些比较简单的变量使用了,让我们来看一个复杂的例子,其中包括了make的函
数、条件表达式和一个系统变量―MAKELEVEL‖的使用:
ifeq (0,${MAKELEVEL}) cur-dir := $(shell pwd) whoami := $(shell whoami) host-type := $(shell arch)
MAKE := ${MAKE} host-type=${host-type} whoami=${whoami} endif
关于条件表达式和函数,我们在后面再说,对于系统变量―MAKELEVEL‖,其意思是,如果
我们的make有一个嵌套执行的动作(参见前面的―嵌套使用make‖),那么,这个变量会
记录了我们的当前Makefile的调用层数。
下面再介绍两个定义变量时我们需要知道的,请先看一个例子,如果我们要定义一个变量
,其值是一个空格,那么我们可以这样来:
nullstring :=
space := $(nullstring) # end of the line
nullstring 是一个Empty变量,其中什么也没有,而我们的space的值是一个空格。因为在
操作符的右边是很难描述一个空格的,这里采用的技术很管用,先用一个 Empty
变量来标
明变量的值开始了,而后面采用―#‖注释符来表示变量定义的终止,这样,我们可以定义
出其值是一个空格的变量。请注意这里关于―#‖的使用,注释符―#‖的这种特性值得我
们注意,如果我们这样定义一个变量:
dir := /foo/bar # directory to put the frobs in
dir这个变量的值是―/foo/bar‖,后面还跟了4个空格,如果我们这样使用这样变量来指
定别的目录——―$(dir)/file‖那么就完蛋了。
还有一个比较有用的操作符是―?=‖,先看示例:
FOO ?= bar
其含义是,如果FOO没有被定义过,那么变量FOO的值就是―bar‖,如果FOO先前被定义过
,那么这条语将什么也不做,其等价于:
ifeq ($(origin FOO), undefined) FOO = bar endif
三、变量高级用法
这里介绍两种变量的高级使用方法,第一种是变量值的替换。
我们可以替换变量中的共有的部分,其格式是―$(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)
这依赖于被替换字串中的有相同的模式,模式中必须包含一个―%‖字符,这个例子同样让
$(bar)变量的值为―a.c b.c c.c‖。
第二种高级用法是——―把变量的值再当成变量‖。先看一个例子: x = y y = z a := $($(x))
在这个例子中,$(x)的值是―y‖,所以$($(x))就是$(y),于是$(a)的值就是―z‖。(注
意,是―x=y‖,而不是―x=$(y)‖)
我们还可以使用更多的层次: x = y y = z z = u
a := $($($(x)))
这里的$(a)的值是―u‖,相关的推导留给读者自己去做吧。
让我们再复杂一点,使用上―在变量定义中使用变量‖的第一个方式,来看一个例子:
x = $(y) y = z z = Hello a := $($(x))
这里的$($(x))被替换成了$($(y)),因为$(y)值是―z‖,所以,最终结果是:a:=$(z), 也就是―Hello‖。
再复杂一点,我们再加上函数:
x = variable1 variable2 := Hello y = $(subst 1,2,$(x)) z = y
a := $($($(z)))
这个例子中,―$($($(z)))‖扩展为―$($(y))‖,而其再次被扩展为―$($(subst 1,2,$
(x)))‖。$(x)的值是―variable1‖,subst函数把―variable1‖中的所有―1‖字串替换
成―2‖字串,于是,―variable1‖变成―variable2‖,再取其值,所以,最终,$(a)的
值就是$(variable2)的值—— ―Hello‖。(喔,好不容易)
在这种方式中,或要可以使用多个变量来组成一个变量的名字,然后再取其值:
first_second = Hello a = first b = second all = $($a_$b)
这里的―$a_$b‖组成了―first_second‖,于是,$(all)的值就是―Hello‖。
再来看看结合第一种技术的例子:
a_objects := a.o b.o c.o 1_objects := 1.o 2.o 3.o
sources := $($(a1)_objects:.o=.c)
这个例子中,如果$(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 c d g q‖,而如果没有定义―do_sort‖,那么:foo := $(sort a d b
g q c),调用的就是strip函数。
当然,―把变量的值再当成变量‖这种技术,同样可以用在操作符的左边:
dir = foo
$(dir)_sources := $(wildcard $(dir)/*.c) define $(dir)_print lpr $($(dir)_sources) endef
这个例子中定义了三个变量:―dir‖,―foo_sources‖和―foo_print‖。
四、追加变量值
我们可以使用―+=‖操作符给变量追加值,如:
objects = main.o foo.o bar.o utils.o objects += another.o
于是,我们的$(objects)值变成:―main.o foo.o bar.o utils.o another.o‖(anothe
r.o被追加进去了)
使用―+=‖操作符,可以模拟为下面的这种例子:
objects = main.o foo.o bar.o utils.o objects := $(objects) another.o
所不同的是,用―+=‖更为简洁。
如果变量之前没有定义过,那么,―+=‖会自动变成―=‖,如果前面有变量定义,那么―
+=‖会继承于前次操作的赋值符。如果前一次的是―:=‖,那么―+=‖会以―:=‖作为其
赋值符,如:
variable := value
variable += more
等价于:
variable := value
variable := $(variable) more
但如果是这种情况:
variable = value variable += more
由于前次的赋值符是―=‖,所以―+=‖也会以―=‖来做为赋值,那么岂不会发生变量的
递补归定义,这是很不好的,所以make会自动为我们解决这个问题,我们不必担心这个问 题。
五、override 指示符
如果有变量是通常make的命令行参数设置的,那么Makefile中对这个变量的赋值会被忽略
。如果你想在Makefile中设置这类参数的值,那么,你可以使用―override‖指