在makefile中除了recipes和和循环扩展变量的定义的任何地方,变量和函数都会被扩展。
Variables and functions in all parts of a makefile are expanded when read, except for
in recipes, the right-hand sides of variable definitions using ‘=’, and the bodies of variable definitions using the define directive.
使用圆括号()或大括号{}引用变量。如$(FOO)或者${FOO}。
对于但字符变量,可以使用$接字符,如用户定义变量$x,自动变量$<,$1等。
使用$$来表示字符$。
变量引用可以在任何上下文:
1 用在变量定义中,被别的变量引用:
1 2 | a := 123 b := abc$a |
2 作为target,如下定义123目标。
1 2 3 | a := 123 $a: echo $@ |
3 用作变量名
1 2 | a := 123 a$a := 1234 |
上述定义了变量a123为1234
4 引用变量的时候,作为变量名的一部分
1 2 3 | a_obj := test.o type := obj b = ${a_${type}} |
上述,b的值为a_obj变量的值。
5 通常不要直接吧变量扩展到Makefile上下文去,而是通过eval。
1 2 | a := b := 3 $(eval $(a)) |
上面这个是对的,执行了 b := 3,而下面这个是错的(直接扩展是怎么实现的,手册并没有提到)。
1 2 | a := b := 3 $(a) |
报错:*** empty variable name. Stop.
recursively expanded variable
使用=定义的变量,定义的时候不会立即进行扩展,而是在使用的时候才进行扩展。
simply expanded variables
使用:=定义的变量,定义的时候,立即扩展得到变量的值。
1 2 3 4 5 | a :=1 b := $a c = $a $(warning $(value b)) $(warning $(value c)) |
value函数可以得到变量的定义,前者b是立即扩展,b的定义就是1。而c是延迟扩展,c的定义是$a。
define通常用来定义一个Multi-Line Variables。
把define的变量通过:=赋值给simple expanded variables,换行符被保留,下面的例子可以证明:
1 2 3 4 5 6 7 | define d y := $1 a: echo a endef c := $(call d,test) $(eval $(c)) |
运行结果和 $(eval $(call d,test))是一样的。
define中可以嵌套定义define。
$(call variable,param,param,...)
它首先把variable后面的参数分别赋给$1,$2等变量,然后在这个临时赋值的上下文中扩展variable,扩展的结果就是call函数的结果。
call在赋给临时变量时,会先扩展param。
call可以嵌套调用。
和其它函数一样,param之间的空白被保留,作为参数的一部分。
思考:
call的时候,它不关心变量的内容是啥,虽然它通常是一段Make syntax,最终的扩展结果会给eval函数使用。call,只是把variable中的变量和函数扩展,这个阶段是在eval之前的,当然variable中也可以包括eval,这样扩展的时候也会执行。
注意:
测试发现,call的variable必须是recursively expanded variable。
value的语法
$(value var)
得到var的定义,对于simple expanded variable它就是变量的值,对于recursively expanded variable,它是变量的定义。
eval的语法:
$(eval param)
首先扩展param,然后扩展的结果作为makefile syntax被parsed。扩展的结果可以包含变量,目标,rules等。
eval函数的结果是空字符串,因此eval函数可以出现在makefile的任何地方,而不引起语法错误。
看个例子:
1 2 3 4 5 6 7 8 9 | define a b := $1 c := /work/$b endef $(eval $(call a,sb)) test: echo $c |
make test,输出结果为/work/。
分析:
执行$(call a,sb)的时候,b还是个未定义的变量,因此$(call a,sb)的结果是:
b := sb
c := /work/
这样,在调用eval的时候,就是单纯按上面定义了b和c。理解了call和eval的原理和过程,就能举一反三分析了。
这样变通一下,c就可以拿到变量b的值了:
define a
$(eval b := $1)
c := /work/$b
endef