参考原文http://blog.csdn.net/liang13664759/article/details/1771246/
Makefile中变量如C\C++中宏一样执行时候自动原模原样展开在使用的地方,与C/C++不同得失,Makefile中可以改变其值。Makefile中变量可以使用在“目标”,“依赖目标”,“命令”或其他部分。
变量名可以包含字符数字下划线(可以数字开头),但是不应该含有“:”、“#”、“=”或是空字符,区分大小写。
一、变量的基础
声明时需要给予初始值,使用时加上“$”符号,最好用“()”或者“{}”把变量包括起来。而使用真是的“$”需要“$$”表示。
变量可以用在许多地方,如规则中的目标、依赖、命令以及新的变量。
二、变量中的变量
①使用“=”,左侧是变量,右侧是变量的值,右侧变量的值可以定义在文件的任何一处,也就是说右侧变量不一定是一已定义好的值,也可以使用后面定义的值。
例如:
foo = $(bar)
bar = $(ugh)
ugh = huh?
all:
echo $(foo)
执行make all会打印出变量$(foo)的值“Huh?”。所以,变量是可以用后面的变量来定义的。
注:这样可能会产生递归定义:
A= $(B)
B=$(A)
这会让make陷入无限的变量展开过程中去,当然,make有检测这样的能力,并会报错。
如果变量中使用函数,这也会让make运行时非常慢。他会使用make的“wildcard”和“shell”发生不可预知的错误。
②“:=”,前面的变量不能使用后面的变量,只能使用已定义好的变量。
x:=foo
y:=$(x) bar
x:=later
等价于
y := foo bar
x := later
而
y := $(x) bar
x := foo
那么y的值是“bar”,而不是“foo, bar”
系统变量“MAKELEVEL”表示,如果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
等价于:
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)”中的所有“.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
“函数”于“条件语句”一同使用的例子:
ifdef do_set
func := sort
else
func := strip
endif
bar := a b d 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:=$(strip a d b g q c),调用strip函数。
“把变量的值当成变量”同样可以用在操作符的左边:
dir = foo
$(dir)_sources := $(wildcard $(dir)/*.c)
define $(die)_print
lpr $($(dir)_sources)#该命令表示把文件发送给打印机
endef
四、追加变量
使用“+=”给变量追加值,如:
objects = main.o foo.o bar.o utils.o
objects += another.o
于是,$(objects)值就变成:“main.o foo.o bar.o utils.o another.o"
等价于:
objects = main.p 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”指示符。
override <variable>=<value>
override <variable>:=<value>
还可以追加
override <variable>+=<more text>
对于多行的变量定义,可以使用define指示符,而define指示符前,也同样可以使用override,如:
override define foo
bar
endef
定义变量foo bar
六、多行变量
使用define关键字设置变量的值可以有换行,有利于一系列的命令。(命令包就是利用该关键字)
define指示符后面跟变量的名字,重起一行定义变量的值,定义以关键字endef结束。工作方式和“=”操作符一样。变量的值可以包含函数、命令、文字或是其他变量。define定义的命令变量中同样要以【Tab】键开头
define two-lines
echo foo
echo $(bar)
endef
七、环境变量
make运行时的系统环境变量可以在make开始运行时被载入到Makefile文件中,但是如果Makefile中定义了这个变量,或是这个变量由make命令行带入,那么系统的环境变量的值将被覆盖(如果make指定了“-e”参数,那么系统环境变量将覆盖Makefile中定义的变量,-e, --environment-overrides环境变量覆盖Makefile文件)
因此,如果我们在环境变量中设置了“CFLAGS”环境变量,那么我们就可以在所有的Makefile中使用这个变量。这对于使用统一的编译参数很方便。如果Makefile中定义了CFLAGS,那么会使用Makefile中的这个变量,如果没有定义则使用系统的环境变量。
当make嵌套调用时,上层Makefile中定义的变量会以系统环境变量的方式传递到下层的Makefile中。默认情况下,只有通过命令行设置的变量会被传递。定义在文件中的变量传递需要export。
不推荐许多的变量定义在系统环境中,这样执行不用的Makefile拥有同一套系统变量,可能会有麻烦。
八、目标变量
前面所述的Makefile中定义的变量都是“全局变量”,整个文件中都可以访问这些变量。当然“自动化变量”除外("$<"、“$@”、“$^”)属于“规则型变量”,这种变量的值依赖于规则的目标和依赖目标的定义。
当然,也可以为某个目标设置局部变量,成为“Target-specific Variable”,它可以和“全局变量”同名,因为他的作用范围只在这条规则以及连带规则中,其值也只在作用范围内有效,不会影响规则链以外的全局变量的值。如下:
<target...>:<variable-assignment>
<target...>:overide<vatiable-assignment>
<vatiable-assignment>可以是前面的各种赋值表达式。“=”、“:=”、“+=”、“?=”。第二条是make命令行带入的变量或是系统环境变量。
示例:
prog:CFLAGS=-g
prog:prog.o foo.o bar.o
$(CC) $(CFLAGS) prog.o foo.o bar.o
prog.o:prog.c
$(CC) $(CFLAGS) prog.c
foo.o:foo.c
$(CC) $(CFLAGS) foo.c
bar.o:bar.c
$(CC) $(CFLAGS) bar.c
实例中,不管全局的$(CFLAGS)的值是什么,在prog以及所引发的所有规则中(prog.o foo.o bar.o),$(CFLAGS)的值都是“-g”
九、模式变量
在GNU的make中,还支持模式变量(Pattern-speific Variable),通过前面,变量可以定义在某个目标上,模式变量的好处就是可以给定一种“模式”,可以把变量定义在符合这种模式的所有目标上。
示例:%.o:CFLAGS=-o
<pattern...>:<variable-assignment>
<pattern...>:override<variable-assignment>
make命令行指定变量override针对系统环境传入变量。