Makefile编写规则(四)常用函数
函数的调用和变量的调用很像。引用变量的格式为$(变量名)
,函数调用的格式如下:
$(<function> <arguments>) 或者是 ${<function> <arguments>}
字符串处理函数
1. 模式字符串替换函数,函数使用格式如下:
$(patsubst <pattern>,<replacement>,<text>)
函数说明:函数功能是查找 text 中的单词是否符合模式 pattern,如果匹配的话,则用 replacement 替换。返回值为替换后的新字符串。实例:
OBJ=$(patsubst %.c,%.o,1.c 2.c 3.c) all: @echo $(OBJ)
执行 make 命令,我们可以得到的值是 "1.o 2.o 3.o",这些都是替换后的值。
2. 字符串替换函数,函数使用格式如下:
$(subst <from>,<to>,<text>)
函数说明:函数的功能是把字符串中的 form 替换成 to,返回值为替换后的新字符串。实例:
OBJ=$(subst ee,EE,feet on the street)
all:
@echo $(OBJ)
执行 make 命令,我们得到的值是“fEEt on the strEEt”。
3. 去空格函数,函数使用格式如下:
$(strip <string>)
函数说明:函数的功能是去掉字符串的开头和结尾的字符串,并且将其中的多个连续的空格合并成为一个空格。返回值为去掉空格后的字符串。实例:
OBJ=$(strip a b c)
all:
@echo $(OBJ)
执行完 make 之后,结果是“a b c”。这个只是除去开头和结尾的空格字符,并且将字符串中的空格合并成为一个空格。
4. 查找字符串函数,函数使用格式如下:
$(findstring <find>,<in>)
函数说明:函数的功能是查找 in 中的 find ,如果我们查找的目标字符串存在。返回值为目标字符串,如果不存在就返回空。实例:
OBJ=$(findstring a,a b c)
all:
@echo $(OBJ)
执行 make 命令,得到的返回的结果就是 "a"。
5. 过滤函数,函数使用格式如下:
$(filter <pattern>,<text>)
函数说明:函数的功能是过滤出 text 中符合模式 pattern 的字符串,可以有多个 pattern 。返回值为过滤后的字符串。实例:
OBJ=$(filter %.c %.o,1.c 2.o 3.s) all: @echo $(OBJ)
执行 make 命令,我们得到的值是“1.c 2.o”
6、反过滤函数,函数使用格式如下:
$(filter-out <pattern>,<text>)
函数说明:函数的功能是功能和 filter 函数正好相反,但是用法相同。去除符合模式 pattern 的字符串,保留符合的字符串。返回值是保留的字符串。实例:
OBJ=$(filter-out 1.c 2.o ,1.o 2.c 3.s) all: @echo $(OBJ)
执行 make 命令,打印的结果是“3.s”。
7. 排序函数,函数使用格式如下:
$(sort <list>)
函数说明:函数的功能是将 <list>
中的单词排序(升序)。返回值为排列后的字符串。sort会去除重复的字符串。实例:
OBJ=$(sort foo bar foo lost)
all:
@echo $(OBJ)
执行 make 命令,我们得到的值是“bar foo lost”
8. 取单词函数,函数使用格式如下:
$(word <n>,<text>)
函数说明:函数的功能是取出函数<text>
中的第n个单词。返回值为我们取出的第 n 个单词。实例:
OBJ=$(word 2,1.c 2.c 3.c) all: @echo $(OBJ)
执行 make 命令,我们得到的值是“2.c”。
文件名操作函数
1. 取目录函数,函数使用格式如下:
$(dir <names>)
函数说明:函数的功能是从文件名序列 names 中取出目录部分,如果没有 names 中没有 "/" ,取出的值为 "./" 。返回值为目录部分,指的是最后一个反斜杠之前的部分。如果没有反斜杠将返回“./”。实例:
OBJ=$(dir src/foo.c hacks)
all:
@echo $(OBJ)
执行 make 命令,我们可以得到的值是“src/ ./”。提取文件 foo.c 的路径是 "/src" 和文件 hacks 的路径 "./"。
2. 取文件函数,函数使用格式如下:
$(notdir <names>)
函数说明:函数的功能是从文件名序列 names 中取出非目录的部分。非目录的部分是最后一个反斜杠之后的部分。返回值为文件非目录的部分。实例:
OBJ=$(notdir src/foo.c hacks)
all:
@echo $(OBJ)
执行 make 命令,我们可以得到的值是“foo.c hacks”。
3. 取后缀名函数,函数使用格式如下:
$(suffix <names>)
函数说明:函数的功能是从文件名序列中 names 中取出各个文件的后缀名。返回值为文件名序列 names 中的后缀序列,如果文件没有后缀名,则返回空字符串。实例:
OBJ=$(suffix src/foo.c hacks)
all:
@echo $(OBJ)
执行 make 命令,我们得到的值是“.c ”。文件 "hacks" 没有后缀名,所以返回的是空值。
4. 取前缀函数,函数使用格式如下:
$(basename <names>)
函数说明:函数的功能是从文件名序列 names 中取出各个文件名的前缀部分。返回值为被取出来的文件的前缀名,如果文件没有前缀名则返回空的字符串。实例:
OBJ=$(notdir src/foo.c hacks)
all:
@echo $(OBJ)
执行 make 命令,我们可以得到值是“src/foo hacks”。获取的是文件的前缀名,包含文件路径的部分。
5. 添加后缀名函数,函数使用格式如下:
$(addsuffix <suffix>,<names>)
函数说明:函数的功能是把后缀 suffix 加到 names 中的每个单词后面。返回值为添加上后缀的文件名序列。实例:
OBJ=$(addsuffix .c,src/foo.c hacks)
all:
@echo $(OBJ)
执行 make 后我们可以得到“sec/foo.c.c hack.c”。我们可以看到如果文件名存在后缀名,依然会加上。
6. 添加前缀名函数,函数使用格式如下:
$(addperfix <prefix>,<names>)
函数说明:函数的功能是把前缀 prefix 加到 names 中的每个单词的前面。返回值为添加上前缀的文件名序列。实例:
OBJ=$(addprefix src/, foo.c hacks)
all:
@echo $(OBJ)
执行 make 命令,我们可以得到值是 "src/foo.c src/hacks" 。我们可以使用这个函数给我们的文件添加路径。
7. 链接函数,函数使用格式如下:
$(join <list1>,<list2>)
函数说明:函数功能是把 list2 中的单词对应的拼接到 list1 的后面。如果 list1 的单词要比 list2的多,那么,list1 中多出来的单词将保持原样,如果 list1 中的单词要比 list2 中的单词少,那么 list2 中多出来的单词将保持原样。返回值为拼接好的字符串。实例:
OBJ=$(join src car,abc zxc qwe)
all:
@echo $(OBJ)
执行 make 命令,我们可以得到的值是“srcabc carzxc qwe”。很显然<list1>
中的文件名比<list2>
的少,所以多出来的保持不变。
8. 获取匹配模式文件名函数,命令使用格式如下:
$(wildcard PATTERN)
函数说明:函数的功能是列出当前目录下所有符合模式的 PATTERN 格式的文件名。返回值为空格分隔并且存在当前目录下的所有符合模式 PATTERN 的文件名。实例:
OBJ=$(wildcard *.c *.h)
all:
@echo $(OBJ)
执行 make 命令,可以得到当前函数下所有的 ".c " 和 ".h" 结尾的文件。这个函数通常跟的通配符 "*" 连用,使用在依赖规则的描述的时候被展开(在这里我们的例子如果没有 wildcard 函数,我们的运行结果也是这样,"echo" 属于 shell 命令,在使用通配符的时通配符自动展开,我们这里只是相要说明一下这个函数在使用时,如果通过引用变量出现在规则中要被使用)。
其他常用函数
1、 $(foreach <var>,<list>,<text>)
函数的功能是:把参数<list>
中的单词逐一取出放到参数<var>
所指定的变量中,然后再执行<text>
所包含的表达式。每一次<text>
会返回一个字符串,循环过程中,<text>
的返所返回的每个字符串会以空格分割,最后当整个循环结束的时候,<text>
所返回的每个字符串所组成的整个字符串(以空格分隔)将会是 foreach 函数的返回值。所以<var>
最好是一个变量名,<list>
可以是一个表达式,而<text>
中一般会只用<var>
这个参数来一次枚举<list>
中的单词。
实例:
name:=a b c d files:=$(foreach n,$(names),$(n).o) all: @echo $(files)
执行 make 命令,我们得到的值是“a.o b.o c.o d.o”。
注意,foreach 中的 <var>
参数是一个临时的局部变量,foreach 函数执行完后,参数<var>
的变量将不再作用,其作用域只在 foreach 函数当中。
2、 $(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
只会有一个被计算。
实例:
OBJ:=foo.c OBJ:=$(if $(OBJ),$(OBJ),main.c) all: @echo $(OBJ)
执行 make 命令我们可以得到函数的值是 foo.c,如果变量 OBJ 的值为空的话,我们得到的 OBJ 的值就是main.c
。
3、 $(call <expression>,<parm1>,<parm2>,<parm3>,...)
expression
参数中的变量$(1)、$(2)、$(3)等,会被参数parm1
,parm2
,parm3
依次取代。而expression
的返回值就是 call 函数的返回值。实例 1:
reverse = $(1) $(2) foo = $(call reverse,a,b) all: @echo $(foo)
那么,foo 的值就是“a b”。当然,参数的次序可以是自定义的,不一定是顺序的,
实例 2:
reverse = $(2) $(1) foo = $(call reverse,a,b) all: @echo $(foo)
此时的 foo 的值就是“b a”。
4、 $(origin <variable>)
origin 函数不像其他的函数,它并不操作变量的值,它只是告诉你这个变量是哪里来的。
注意: variable 是变量的名字,不应该是引用,所以最好不要在 variable 中使用“$”字符。origin 函数会员其返回值来告诉你这个变量的“出生情况”。
下面是origin函数返回值:
- “undefined”:如果<variable>从来没有定义过,函数将返回这个值。
- “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
,我们想去判断一下这个变量是不是环境变量,如果是我们就把它重定义了。如果是非环境变量,那么我们就不重新定义它。于是,我们在 Makefile 中,可以这样写
ifdef bletch ifeq "$(origin bletch)" "environment" bletch = barf,gag,etc endif endif
当然,使用override
关键字不就可以重新定义环境中的变量了吗,为什么需要使用这样的步骤?是的,我们用override
是可以达到这样的效果的,可是override
会把从命令行定义的变量也覆盖了,而我们只想重新定义环境传来的,而不是重新定义命令行传来的。