目录
我们继续Makefile函数使用的学习,上一节可查看:↓传送门↓。
一、foreach函数
foreach函数和其它函数不同,这个函数是用来做循环使用的,Makefile中的foreach函数几乎是按照Unix标准Shell的for语句或者是C-Shell中的foreach语句构建的,语法是:
$(foreach <var>,<list>,<text>)
意义是将参数<list>中的单词逐一取出放到参数<var>所指定的变量中,然后再执行<text>所包含的表达式。每一次<text>会返回一个字符串,循环过程中,<text>的所返回的每个字符串会以空格分隔,最后当整个循环结束时,<text>所返回的每个字符串所组成的整个字符串就是foreach函数的返回值。
所以<var>最好是一个变量名,<list>可以是一个表达式,<text>中一般会使用<var>这个参数来依次枚举<list>中的单词,如:
names:=a b c d
files:=$(foreach n,$(names),$(n).o)
例中,$(names)中的单词被依次取出,并存到变量n中,$(n).o每次依据$(n)计算出一个值,这些值以空格分隔,最后作为foreach函数的返回。所以,$(files)的值是a.o b.o c.o d.o。
foreach中的<var>参数是一个临时的局部变量,foreach函数执行完成后,参数<var>的变量将不再作用,作用域只在foreach函数当中。
二、if函数
if函数类似于GNU的make所支持的条件语句--ifeq,if函数的语法是:
$(if <condition>,<then-part>)
或者
$(if <condition>,<then-part>,<else-part>)
可见if函数还可以包含“else”部分,或者不包含。if函数的参数可以是两个,也可以是三个。<condition>参数是if的表达式,如果其返回的为非空字符串,那么这个表达式就相当于返回真,于是<then-part>会被计算,否则<else-part>会被计算。
if函数的返回值是,如果<condition>为真(非空字符串),那么<then-part>会是这个函数的返回值,如果<condition>为假(空字符串),那么<else-part>会是整个函数的返回值。此时如果<else-part>没有被定义,那么整个函数返回空字串。
所以<then-part>和<else-part>只有一个会被计算。
三、call函数
call函数是唯一一个可以用来创建新的参数化的函数,语法是:
$(call <expression>,<parm1>,<parm2>,...,<parmn>)
当make执行这个函数时,<expression>参数中的变量,如$(1)、$(2)等,会被参数<parm1>、<parm2>……<parmn>依次取代,而<expression>的返回值就是call函数的返回值。例如:
reverse=$(1) $(2)
foo=$(call reverse,a,b)
foo的值就是a b。参数的次序是可以自定义的,不一定是顺序的,如:
reverse=$(2) $(1)
foo=$(call reverse,a,b)
此时foo的值是b a。
在向call函数传递参数时要注意空格的使用,call函数在处理参数时,第2个及其之后的参数中的空格会被保留,可能会造成奇怪的结果,所以在向call函数提供参数时,最安全的做法是去除所有多余的空格。
四、origin函数
origin函数不操作变量,其作用是告诉你这个变量的来源,语法如下:
$(origin <variable>)
这里的<variable>是变量名字,不应该是引用。所以最好不要在<variable>中使用$字符。
下面是origin函数的返回值:
①undefined
如果<variable>从来没有定义过,origin函数返回这个值undefined。
②default
如果<variable>是一个默认的定义,比如“CC”这个变量。
③environment
如果<variable>是一个环境变量,并且当Makefile被执行时,-e参数没有被打开。
④file
如果<variable>这个变量被定义在Makefile中。
⑤command line
如果<variable>这个变量是被命令行定义的。
⑥override
如果<variable>是被override指示符重新定义的。
⑦automatic
如果<variable>是一个命令行运行中的自动化变量。
这些信息对我们编写Makefile是非常有用的,假设我们有一个Makefile,其包含了一个定义文件Make.def,在Make.def中定义了一个变量“bletch”,而我们的环境中也有一个环境变量“bletch”,此时我们需要判断一下,如果变量来源于环境,这样做将会重新定义这个变量。如果来源于Make.def或者是命令行等非环境的,我们就不会重新定义。于是我们在Makefile中可以这样写:
ifdef bletch
ifeq "$(origin bletch)" "environment"
bletch = barf, gag, etc.
endif
endif
五、shell函数
shell函数的参数是操作系统Shell的命令,它和反引号“ ‘ ”是相同的功能。shell函数把执行操作系统命令后的输出作为函数返回。我们可以用操作系统命令以及字符串处理命令awk、sed等命令来生成一个变量,如:
contents:=$(shell cat foo)
files:=$(shell echo *.c)
这个函数会新生成一个Shell程序来执行命令,如果你的Makefile中有一些比较复杂的规则,并且大量使用了这个函数,这样做对系统性能影响很大。尤其是Makefile的隐晦规则可能会让你的shell函数执行的次数比你想象的多很多。
六、控制make的函数
make提供了一些函数来控制make的运行,通常你需要检测一些运行Makefile时的运行时信息,并且根据这些信息来决定make继续执行还是停止。
$(error <text...>)
产生一个致命错误,<text...>是错误信息,error函数不会在被使用时就立即产生错误信息,所以如果将其定义在某个变量中,并在后续的脚本中使用这个变量,也是可以的。例如:
#例1
ifdef ERROR_001
$(error error is $(ERROR_001))
endif
#例2
ERR=$(error found an error!)
.PHONY: err
err:$(ERR)
例1会在变量ERROR_001定义之后执行时产生error调用,例2在目录err被执行时才发生error调用。
$(warning <text...>)
这个函数与error类似,只是它不会让make退出,只是输出一段警告信息,而make继续执行。