Trackback: http://tb.blog.csdn.net/TrackBack.aspx?PostId=2895
四、
foreach
函数
foreach
函数和别的函数非常的不一样。因为这个函数是用来做循环用的,
Makefile
中的
foreach
函数几乎是仿照于
Unix
标准
Shell
(
/bin/sh
)中的
for
语句,或是
C-Shell
(
/bin/csh
)中的
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)
上面的例子中,
$(name)
中的单词会被挨个取出,并存到变量“
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
函数来向这个表达式传递参数。其语法是:
$(call <expression>,<parm1>,<parm2>,<parm3>...)
当
make
执行这个函数时,
<expression>
参数中的变量,如
$(1)
,
$(2)
,
$(3)
等,会被参数
<parm1>
,
<parm2>
,
<parm3>
依次取代。而
<expression>
的返回值就是
call
函数的返回值。例如:
reverse = $(1) $(2)
foo = $(call reverse,a,b)
那么,
foo
的值就是“
a b
”。当然,参数的次序是可以自定义的,不一定是顺序的,如:
reverse = $(2) $(1)
foo = $(call reverse,a,b)
此时的
foo
的值就是“
b a
”。
七、
origin
函数
origin
函数不像其它的函数,他并不操作变量的值,他只是告诉你你的这个变量是哪里来的?其语法是:
$(origin <variable>)
注意,
<variable>
是变量的名字,不应该是引用。所以你最好不要在
<variable>
中使用“
$
”字符。
Origin
函数会以其返回值来告诉你这个变量的“出生情况”,下面,是
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
当然,你也许会说,使用
override
关键字不就可以重新定义环境中的变量了吗?为什么需要使用这样的步骤?是的,我们用
override
是可以达到这样的效果,可是
override
过于粗暴,它同时会把从命令行定义的变量也覆盖了,而我们只想重新定义环境传来的,而不想重新定义命令行传来的。
八、
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
函数不会在一被使用就会产生错误信息,所以如果你把其定义在某个变量中,并在后续的脚本中使用这个变量,那么也是可以的。例如:
示例一:
ifdef ERROR_001
$(error error is $(ERROR_001))
endif
示例二:
ERR = $(error found an error!)
.PHONY: err
err: ; $(ERR)
示例一会在变量
ERROR_001
定义了后执行时产生
error
调用,而示例二则在目录
err
被执行时才发生
error
调用。
$(warning <text ...>)
这个函数很像
error
函数,只是它并不会让
make
退出,只是输出一段警告信息,而
make
继续执行。