makefile必知必会(II)

  • 时间:
  • 来源:互联网
  • 文章标签:

makefile必知必会(II)


定义变量

makefile的变量定义有三种方式

1.        立即赋值 a:=b

2.        延迟赋值 a=b

3.        条件赋值 a?=b

4.        附加赋值 a+=b

它们之间的区别是,

第一种方式,会立即计算b的值,并赋值给a;

第二种方式,相当于C++和java的引用。如果后面b的值改变了,那么a的值也会改变;

第三种方式,如果a没有定义,则相当于a=b ,否则不执行任何操作;

第四种方式,将b的值添加到a原有的值后面,再赋值给a。

 

获取变量值

$(var) //表示取变量var的值,记得当变量名多于一个字符时,使用”()”.

 

定义宏

define function

xxx // 具体的内容

endef

需要指出的是,虽然形式上类似函数,但是实际内容只是字符串替换,这与C中的宏函数是一样的。

 

什么时候计算变量

makefile的解析分为两个阶段,第一阶段生成规则和依赖关系,第二阶段执行规则;

只有立即展开的变量会在第一阶段计算,而延后展开的变量会在第二阶段计算。

立即与延后展开的规则

表达式

何时扩展a

何时扩展b

a=b

立即

延后

a?=b

立即

延后

a:=b

立即

立即

a+=b

立即

取决于之间a的定义方式
如果是a:=,在立即
否则延后

define a
b …
endef

立即

延后

a : b
    c …

立即

立即
(命令中的变量,即变量c是延后展开)

 

 

eval

有两个特点

1. 做两次变量展开;以$(eval var),首先会对var做一次变量展开,然后对展开后的结果,再执行一次变量展开。详细的描述请各位参考链接

2. $(eval var)返回为空。这个特性被大量使用于宏定义define中。

  看下面这个例子:

define import_target

  include $(1)

  _PREFIXID := $(if$2, $2, TARGET)

  $(_ PREFIXID)

endef

按上面定义的宏,当去计算a:=$(call  import_target)时,几乎总是会报错。

原因是宏定义只是简单的做字符串替换,一经替换后,原来看起来是一行语句,一下子就变成多行,从而导致makefile解析错误。

  于是只能使用“\”将各个语句连接为一行。

define import_target

  include $(1) \

   _PREFIXID := $(if $2, $2,TARGET) \

  $(_ PREFIXID)

endef

  这样做相当于

         include $(1) _PREFIXID := $(if $2, $2, TARGET)  $(_ PREFIXID)

  显然,肯定还是报解析错误。

 最终解决方案,将各个子语句使用$(eval )包裹,

 define import_target

$(eval include $(1)) \

$(eval _PREFIXID := $(if $2,$2, TARGET)) \

$(_ PREFIXID)

endef 

解析时,makefile先对$(1)做展开,假设结果为xxx,这是第一次;然后执行include xxx,这是第二次展开。执行完后,整个$(eval include $(1))表达式返回值为空。这样解析错误解决了,而且 import_target的返回结果又正好是_ PREFIXID的值。

 

call

格式:$(call func,param1, param2,..)

实现自定义函数调用。func使用define定义。 call会自动将param1的值赋值给func中的$1变量,将param2赋值给$2变量,依次类推。

小心空格

变量赋值a:=   b, 不会将b前面的空格赋值给a

大部分函数调用,特别是$(call func, param) 如果参数前面有空格,则会将空格连同参数一起传入。因此要特别小心。

使用$(strip var)是个好习惯,可以避免不小心引入前置或者后置的空格导致的问题。

本文链接http://www.taodudu.cc/news/show-647522.html