#使用函数
在Makefile中可以使用函数来处理变量, 从而让我们的命令或是规则更为的灵活且具有智能
make所支持的函数不是很多, 不过已经足够了. 函数调用后, 函数的返回值可以当做变量来使用
一. 函数的调用语法
#>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
#函数调用, 很像变量的使用, 也是以 '$' 来标识的, 其语法如下:
$(<function> <arguments> )
#或是
${<function> <arguments>}
#<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
<function>就是函数名, <arguments>是函数的参数, 参数间以逗号 ',' 分隔. 而函数名和
参数之间以 "空格" 分隔. 函数调用以 '$' 开头, 以圆括号或花括号把函数名和参数括起.感觉
很像一个变量. 函数中的参数可以使用变量, 为了风格的统一, 函数和变量的括号最好一样, 如
使用 "$(subst a,b,$(x))" 这样的形式, 而不是 "$(subst a,b,${x})" 的形式.
#>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
#Exampke make start
#例1-1
comma:= ,
empty:=
space:= $(empty) $(empty)
foo:= a b c
bar:= $(subst $(space),$(comma),$(foo))
#Example make end
#<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
在这个示例中, $(comma)的值是一个逗号. $(space)使用了$(empty)定义了一个空格, $(foo)的
值是 "a b c", $(bar)的定义调用了函数 "subst", 这是一个替换函数, 函数有三个参数, 第一
个参数是被替换字串, 第二个参数是替换字串, 第三个参数是替换操作作用的字串. 这个函数也
就是把$(foo)中的空格替换成逗号, 所以$(bar)的值是 "a,b,c".
二. 字符串处理函数
1. 字符串替换函数 subst
名 称: subst
原 型: $(subst <from>,<to>,<text> )
功 能: 把字串 <text> 中的 <from> 字符串替换成 <to>.
返回值: 函数返回被替换过后的字符串.
示 例: $(subst ee,EE,feet on the street)
说 明: 把 "feet on the street" 中的 "ee" 替换成 "EE", 返回 "fEEt on the strEEt".
2. 模式字符串替换函数 patsubst
名 称:patsubst
原 型: $(patsubst <pattern>,<replacement>,<text> )
功 能:查找 <text> 中的单词(单词以 "空格", "Tab" 或 "回车" "换行" 分隔)是否符合模式
<pattern>, 如果匹配的话, 则以 <replacement> 替换. 这里, <pattern> 可以包括通
配符 '%', 表示任意长度的字串. 如果 <replacement> 中也包含 '%', 那么,该字符将
是 <pattern> 中的那个 '%' 所代表的字串.
返回值:函数返回被替换过后的字符串。
示 例: $(patsubst %.c,%.o,x.c.c bar.c)
说 明: 把字串 "x.c.c bar.c" 符合模式 "%.c" 的单词替换成 "%.o"
返回结果是 "x.c.o bar.o"
备 注: 这和我们前面 "变量章节" 说过的相关知识有点相似. 如:
"$(var:<pattern>=<replacement> )" 相当于
"$(patsubst <pattern>,<replacement>,$(var))", 而
"$(var: <suffix>=<replacement> )" 则相当于
"$(patsubst %<suffix>,%<replacement>,$(var))".
示 例: objects = foo.o bar.o baz.o, 那么,
"$(objects:.o=.c)" 和
"$(patsubst %.o,%.c,$(objects))" 是一样的.
3. 去空格函数 strip
名 称: strip
原 型: $(strip <string>)
功 能: 去掉 <string> 字串中开头和结尾的空字符
返回值: 返回被去掉空格的字符串值
示 例: $(strip a b c )
说 明: 把字串 "a b c " 去到开头和结尾的空格, 结果是 "a b c".
4. 查找字符串函数 findstring
名 称: 查找字符串函数——findstring。
原 型: $(findstring <find>,<in> )
功 能: 在字串<in>中查找<find>字串
返回值: 如果找到, 那么返回 <find>, 否则返回空字符串
示 例: $(findstring a,a b c)
$(findstring a,b c)
说 明: 第一个函数返回 "a" 字符, 第二个返回空字符串.
5. 过滤函数 filter
名 称: 过滤函数——filter。
原 型: $(filter <pattern...>,<text> )
功 能: 以 <pattern> 模式过滤 <text> 字符串中的单词, 保留符合模式 <pattern> 的单词.
可以有多个模式.
返回值: 返回符合模式 <pattern> 的字串.
示 例: sources := foo.c bar.c baz.s ugh.h
foo: $(sources)
cc $(filter %.c %.s,$(sources)) -o foo
说 明: $(filter %.c %.s,$(sources)) 返回的值是 "foo.c bar.c baz.s".
6. 反过滤函数 filter-out
名 称: filter-out
原 型: $(filter-out <pattern...>,<text> )
功 能: 以 <pattern> 模式过滤 <text> 字符串中的单词, 去除符合模式 <pattern> 的单词,
可以有多个模式.
返回值: 返回不符合模式 <pattern> 的字串.
示 例: objects="main1".o foo.o main2.o bar.o
mains=main1.o main2.o
$(filter-out $(mains),$(objects))
说 明: 返回值是 "foo.o bar.o".
7. 排序函数 sort
名 称: sort
原 型: $(sort <list> )
功 能: 给字符串<list>中的单词排序(升序).
返回值: 返回排序后的字符串
示 例: $(sort foo bar lose)
说 明: 返回 "bar foo lose"
备 注: sort函数会去掉 <list> 中相同的单词.
8. 取单词函数 word
名 称: word
原 型: $(word <n>,<text> )
功 能: 取字符串<text>中第<n>个单词(从1开始)
返回值: 返回字符串 <text> 中第 <n> 个单词. 如果 <n> 比 <text> 中的单词数要大, 那么返
回空字符串.
示 例: $(word 2, foo bar baz)
说 明: 返回值是 "bar"
9. 取单词串函数 wordlist
名 称: wordlist
原 型: $(wordlist <s>,<e>,<text> )
功 能: 从字符串 <text> 中取从 <s> 开始到 <e> 的单词串. <s> 和 <e> 是一个数字.
返回值: 返回字符串 <text> 中从 <s> 到 <e> 的单词字串.如果 <s> 比 <text> 中的单词数要
大, 那么返回空字符串. 如果 <e> 大于 <text> 的单词数, 那么返回从 <s> 开始, 到
<text> 结束的单词串.
示 例: $(wordlist 2, 3, foo bar baz)
说 明: 返回值是 "bar baz"
10. 单词个数统计函数 words
名 称: words
原 型: $(words <text> )
功 能: 统计<text>中字符串中的单词个数
返回值: 返回<text>中的单词数
示 例: $(words, foo bar baz)
说 明: 返回值是 "3"
备 注: 如果我们要取 <text> 中最后的一个单词, 我们可以这样:
$(word $(words <text> ), <text> )。
11. 首单词函数 firstword
名 称: firstword
原 型: $(firstword <text> )
功 能: 取字符串<text>中的第一个单词
返回值: 返回字符串 <text> 的第一个单词
示 例: $(firstword foo bar)
说 明: 返回值是 "foo"
备 注: 这个函数可以用word函数来实现: $(word 1,<text> )
以上是所有的字符串操作函数, 如果搭配混合使用, 可以完成比较复杂的功能. 这里, 举一
个现实中应用的例子. 我们知道, make使用 "VPATH" 变量来指定 "依赖文件" 的搜索路径.于是
我们可以利用这个搜索路径来指定编译器对头文件的搜索路径参数CFLAGS, 如:
override CFLAGS += $(patsubst %,-I%,$(subst :, ,$(VPATH)))
如果我们的 "$(VPATH)" 值是 "src:../headers", 那么将返回 "-Isrc -I../headers", 这正是
cc或gcc搜索头文件路径的参数.
三. 文件名操作函数
1. 取目录函数 dir
名 称: dir
原 型: $(dir <names...> )
功 能: 从文件名序列 <names> 中取出目录部分. 目录部分是指最后一个反斜杠 '/' 之前的部
分.
返回值: 返回文件名序列 <names> 的目录部分。
示 例: $(dir src/foo.c hacks)
说 明: 返回值是 "src/ ./"
2. 取文件函数 notdir
名 称: notdir
原 型: $(notdir <names...> )
功 能: 从文件名序列 <names> 中取出非目录部分.
返回值: 返回文件名序列 <names> 的非目录部分
示 例: $(notdir src/foo.c hacks)
说 明: 返回值是 "foo.c hacks"
3. 取后缀函数 suffix
名 称: suffix
原 型: $(suffix <names...> )
功 能: 从文件名序列 <names> 中取出各个文件名的后缀
返回值: 返回文件名序列 <names>的后缀序列, 如果文件没有后缀, 则返回空字串.
示 例: $(suffix src/foo.c src-1.0/bar.c hacks)
说 明: 返回值是 ".c .c"
4. 取前缀函数 basename
名 称: basename
原 型: $(basename <names...> )
功 能: 从文件名序列 <names> 中取出各个文件名的前缀部分
返回值: 返回文件名序列 <names> 的前缀序列
示 例: $(basename src/foo.c src-1.0/bar.c hacks)
说 明: 返回值是 "src/foo src-1.0/bar hacks"
5. 加后缀函数 addsuffix
名 称: addsuffix
原 型: $(addsuffix <suffix>,<names...> )
功 能: 把后缀 <suffix> 加到 <names> 中的每个单词后面
返回值: 返回加过后缀的文件名序列
示 例: $(addsuffix .c,foo bar)
说 明: 返回值是 "foo.c bar.c"
6. 加前缀函数 addprefix
名 称: addprefix
原 型: $(addprefix <prefix>,<names...> )
功 能: 把前缀 <prefix> 加到 <names> 中的每个单词后面
返回值: 返回加过前缀的文件名序列
示 例: $(addprefix src/,foo bar)
说 明: 返回值是 "src/foo src/bar"
7. 连接函数 join
名 称: join
原 型: $(join <list1>,<list2> )
功 能: 把 <list2> 中的单词对应地加到 <list1> 的单词后面.如果 <list1> 的单词个数要比
<list2>的多, 那么, <list1> 中的多出来的单词将保持原样. 如果 <list2> 的单词个
数要比 <list1> 多, 那么, <list2> 多出来的单词将被复制到 <list1> 中.
返回值: 返回连接过后的字符串
示 例: $(join aaa bbb , 111 222 333)
说 明: 返回值是 "aaa111 bbb222 333"
四. foreach 函数
介 绍: foreach与别的函数不同. 因为这个函数是用来做循环用的, Makefile中的foreach函数
几乎是仿照于Unix标准Shell中的for语句, 或是C-Shell(/bin/csh)中的foreach语句而
构建的.
名 称: foreach
原 型: $(foreach <var>,<list>,<text> )
功 能: 把参数 <list> 中的单词逐一取出放到参数 <var>所指定的变量中,然后再执行 <text>
所包含的表达式. 每一次 <text> 会返回一个字符串, 循环过程中, <text>的所返回的
每个字符串会以空格分隔, 最后当整个循环结束时, <text>所返回的每个字符串所组成
的整个字符串是foreach函数的返回值.
返回值: 字符串
示 例: 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
原 型: $(if <condition>,<then-part> )
$(if <condition>,<then-part>,<else-part> )
功 能: if函数可以包含else部分. 即if函数的参数可以是两个, 也可以是三个. <condition>
参数是if的表达式, 若返回非空字符串, 表达式为真, <then-part>会被计算,否则
<else-part> 会被计算.
返回值: 如果 <condition>为真, <then-part>会是整个函数的返回值, 否则, <else-part>会是
整个函数的返回值, 如果 <else-part>没有被定义, 整个函数返回空字串.
说 明: if函数很像GNU的make所支持的条件语句ifeq.
六、call函数
介 绍: call函数是唯一一个可以用来创建新的参数化的函数. 你可以写一个非常复杂的表达式
这个表达式中, 你可以定义许多参数, 然后你可以用call函数来向这个表达式传递参数
名 称: call
原 型: $(call <expression>,<parm1>,<parm2>,<parm3>...)
功 能: 当make执行函数时, <expression>中的变量, 如$(1),$(2),$(3)等, 会被参数 <parm1>
<parm2>, <parm3>依次取代. 而 <expression>的返回值就是call函数的返回值.
返回值: <expression>的返回值
示 例: 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
原 型: $(origin <variable> )
功 能: <variable>是变量的名字, 不应该是引用. 最好不要在 <variable>中使用 '$' 字
符. Origin以其返回值来告诉你这个变量的 "出生情况".
返回值:
undefined: 变量从未定义过
default: 变量是一个默认的定义, 比如 "CC".
environment:环境变量, 并且当Makefile被执行时, "-e" 参数没有被打开.
file: 变量定义在Makefile中.
command line: 变量是被命令行定义的.
override: 变量override指示符重新定义的.
automatic: 变量是一个命令运行中的自动变量.
示 例: 这些信息对于我们编写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
原 型: $(origin <shell-command> )
功 能: 它和反引号 '`' 是相同的功能. 这就是说, shell函数把执行操作系统命令后的输出作
为函数返回.
返回值: shell命令的输出
示 例: 我们可以用操作系统命令以及字符串处理命令awk,sed等等命令来生成一个变量
contents := $(shell cat foo)
files := $(shell echo *.c)
说 明: 该函数会新生成一个Shell程序来执行命令,所以要注意其运行性能, 如果你的Makefile
中有一些比较复杂的规则, 并大量使用了这个函数, 这对于你的系统性能是有害的. 特
别是Makefile的隐晦的规则可能会让你的shell函数执行的次数比你想像的多得多.
九. 控制make的函数
make提供了一些函数来控制make的运行. 通常, 你需要检测一些运行Makefile时的运行时信
息, 并且根据这些信息来决定make是否继续运行.
1. 产生错误函数error
名 称: error
原 型: $(error <text ...> )
功 能: 产生一个致命的错误, <text ...>是错误信息. 注意,error函数不会在一被使用就会产
生错误信息, 如果你把其定义在某个变量中, 并在后续的脚本中使用这个变量, 那么也
是可以的.
示 例: ifdef ERROR_001
$(error error is $(ERROR_001))
endif
在变量ERROR_001定义了后执行时产生error调用.
ERR = $(error found an error!)
.PHONY: err
err:
$(ERR)
在目标err被执行时才发生error调用
2. 产生警告信息函数warning
名 称: warning
原 型: $(warning <text ...> )
功 能: 这个函数很像error函数, 只是它并不会让make退出, 只是输出一段警告信息,而make继
续执行.
【2006-12-26】
文章评论(0条评论)
登录后参与讨论