规则
伪目标
变量
变量定义的3种方式
1 foo = bar (递归展开式变量)
会在引用$(foo)地方原地替换,直到不能再替换,这种方式称之为递归展开式变量1
2
3
4foo = $(bar)
bar = $(ugh)
ugh = Huh?
all @echo $(foo)以上例子会在@echo $(foo) 地方递归展开
缺点一 : 是当嵌套定义foo = $(foo) bar
时讲进入死循环,导致Make失败
其他例子
x = $(y)
y = $(x) $(z)
同样会陷入死循环,所以这种定义方法只推荐在不引用变量的时候应用
缺点二 这种定义中如果使用函数,只会在变量被引用时展开,而不是在定义时展开
会使得Make的效率降低,另外有可能会在变量函数的引用会出现非预期结果,特别当变量
定义引用到shell wildcard 函数的情况下,出现不可控的结果1
2
3
4
5
6x = foo
y = $(x) bar //$(x) 不会被立即替换,只有在$(y)被用到的地方才用x的值替换
x = later //将会覆盖 原来的 x ,
等价于
y = later bar
x = later
2 foo := bar (直接展开式变量)
1
2
3
4
5
6x := foo
y := $(x) bar ; 会立即替换成 foo bar
x := later
等价于
y := foo bar
x := later bar在复杂的Makefile中,推荐使用立即展开式变量,变量的定义会比较明确 ,也和大多数变成语言中的变量定义使用方法一致。
尽量避免和减少使用第一种递归式变量的使用定义空格
dir := /foo/bar # directory to put the frobs in
变量“dir”的值是“/foo/bar ”(后面有 4 个空格),这可能并不是想要实现的。如果一个文件以它作为路径来表示“$(dir)/file”,那么大错特错了。
在书写 Makefile 时。推荐将注释书写在独立的行或者多行,防止出现上边例子中
的意外情况,而且将注释书写在独立的行也使得 Makefile 清晰,便于阅读。对于特殊
的定义,比如定义包含一个或者多个空格空格的变量时进行详细地说明和注释。
如果定义个空格变量1
2nullstring :=
space := $(nullstring) # end of the line3 foo ?= bar 条件赋值操作符
只有变量之前没有赋值的情况下才会对这个变量赋值,如果之前已经定义了,就不改变原来的值
1
2
3
4
5FOO ?= bar
其等价于:
ifeq ($(origin FOO), undefined)
FOO = bar
endif4 foo += jar 追加变量值
1
2
3
4
5
6objects = main.o foo.o bar.o utils.o
objects += another.o
上边的两个操作之后变量“objects”的值就为:“main.o foo.o bar.o utils.o another.o”。
使用“+=”操作符,相当于:
objects = main.o foo.o bar.o utils.o
objects := $(objects) another.o5 define 定义多行变量
1
2
3
4define two-lines
echo foo
echo $(bar)
endef6 override 变量
1
2
3
4
5
6override foo = bar
override foo := bar
override define two-lines
foo
$(bar)
endefoverride定义变量是,防止变量的值被命令行指定
变量的高级用法
变量的替换引用
格式为“$(VAR:A=B)”(或者“${VAR:A=B}”),意思是,
替换变量“VAR”中所有“A”字符结尾的字为“B”结尾的字。“结尾”的含义是空格
之前(变量值多个字之间使用空格分开)。而对于变量其它部分的“A”字符不进行替
换。例如:1
2foo := a.o b.o c.o
bar := $(foo:.o=.c)
变量的替换引用其实是函数“patsubst”(参考 8.2 文本处理函数 一节)的一个简化实现
所实现功能相同。例如:1
2foo := a.o b.o c.o
bar := $(foo:%.o=%.c)
这个例子同样使变量“bar”的值为“a.c b.c c.c”。这种格式的替换引用方式比第一种方式更通用
变量的嵌套引用1
2
3
4x = $(y)
y = z
z = Hello
a := $($(x))
a的值最后为Hello,嵌套引用往往最后一个变量定义要用立即展开变量定义,有点像C语言的指针