字符串处理函数
1.$(subst FROM,TO,TEXT)
函数名称:字符串替换函数—subst。
函数功能:把字串“TEXT”中的“FROM”字符替换为“TO”。
返 回 值:替换后的新字符串。
2.$(patsubst PATTERN,REPLACEMENT,TEXT)
函数名称:模式替换函数—patsubst。
函数功能:搜索“TEXT”中以空格分开的单词,将否符合模式“TATTERN”替换为“REPLACEMENT”。参数“PATTERN”中可以使用模式通配符“%”来代表一个单词中的若干字符。如果参数“REPLACEMENT”中也包含一个“%”,那么“REPLACEMENT”中的“%”将是“TATTERN”中的那个“%”所代表的字符串。在“TATTERN”和“REPLACEMENT”中,只有第一个“%”被作为模式字符来处理,后续的作为字符本上来处理。在两个参数中当使用第一个“%”本是字符本身时,可使用反斜杠“\”对它进行转义处理。
返 回 值:替换后的新字符串。
函数说明:参数“TEXT”单词之间的多个空格在处理时被合并为一个空格,但前导和结尾空格忽略。
3.$(strip STRINT)
函数名称:去空格函数—strip。
函数功能:去掉字串(若干单词,使用若干空字符分割)“STRINT”开头和结尾的空字符,并将其中多个连续空字符合并为一个空字符。
返 回 值:无前导和结尾空字符、使用单一空格分割的多单词字符串。
函数说明:空字符包括空格、[Tab]等不可显示字符。
4.$(findstring FIND,IN)
函数名称:查找字符串函数—findstring。
函数功能:搜索字串“IN”,查找“FIND”字串。
返 回 值:如果在“IN”之中存在“FIND”,则返回“FIND”,否则返回空。
函数说明:字串“IN”之中可以包含空格、[Tab]。搜索需要是严格的文本匹配。
5.$(filter PATTERN…,TEXT)
函数名称:过滤函数—filter。
函数功能:过滤掉字串“TEXT”中所有不符合模式“PATTERN”的单词,保留所有符合此模式的单词。可以使用多个模式。模式中一般需要包含模式字符“%”。存在多个模式时,模式表达式之间使用空格分割。
返 回 值:空格分割的“TEXT”字串中所有符合模式“PATTERN”的字串。
函数说明:“filter”函数可以用来去除一个变量中的某些字符串,我们下边的例子中就是用到了此函数。
6.$(filter-out PATTERN...,TEXT)
函数名称:反过滤函数—filter-out。
函数功能:和“filter”函数实现的功能相反。过滤掉字串“TEXT”中所有符合模式“PATTERN”的单词,保留所有不符合此模式的单词。可以有多个模式。存在多个模式时,模式表达式之间使用空格分割。。
返 回 值:空格分割的“TEXT”字串中所有不符合模式“PATTERN”的字串。
函数说明:“filter-out”函数也可以用来去除一个变量中的某些字符串,(实现和“filter”函数相反)。
7.$(sort LIST)
函数名称:排序函数—sort。
函数功能:给字串“LIST”中的单词以首字母为准进行排序(升序),并取掉重复的单词。
返 回 值:空格分割的没有重复单词的字串。
函数说明:两个功能,排序和去字串中的重复单词。可以单独使用其中一个功能。
8.$(word N,TEXT)
函数名称:取单词函数—word。
函数功能:取字串“TEXT”中第“N”个单词(“N”的值从1开始)。
返 回 值:返回字串“TEXT”中第“N”个单词。
函数说明:如果“N”值大于字串“TEXT”中单词的数目,返回空字符串。如果“N”为0,出错!
9.$(wordlist S,E,TEXT)
函数名称:取字串函数—wordlist。
函数功能:从字串“TEXT”中取出从“S”开始到“E”的单词串。“S”和“E”表示单词在字串中位置的数字。
返 回 值:字串“TEXT”中从第“S”到“E”(包括“E”)的单词字串。
函数说明:“S”和“E”都是从1开始的数字。当“S”比“TEXT”中的字数大时,返回空。如果“E”大于“TEXT”字数,返回从“S”开始,到“TEXT”结束的单词串。如果“S”大于“E”,返回空。
10.$(words TEXT)
函数名称:统计单词数目函数—words。
函数功能:字算字串“TEXT”中单词的数目。
返 回 值:“TEXT”字串中的单词数。
11.$(firstword NAMES…)
函数名称:取首单词函数—firstword。
函数功能:取字串“NAMES…”中的第一个单词。
返 回 值:字串“NAMES…”的第一个单词。
函数说明:“NAMES”被认为是使用空格分割的多个单词(名字)的序列。函数忽略“NAMES…”中除第一个单词以外的所有的单词。
二、文件名处理函数
1.$(dir NAMES…)
函数名称:取目录函数—dir。
函数功能:从文件名序列“NAMES…”中取出各个文件名目录部分。文件名的目录部分就是包含在文件名中的最后一个斜线(“/”)(包括斜线)之前的部分。
返 回 值:空格分割的文件名序列“NAMES…”中每一个文件的目录部分。
函数说明:如果文件名中没有斜线,认为此文件为当前目录(“./”)下的文件。
2.$(notdir NAMES…)
函数名称:取文件名函数——notdir。
函数功能:从文件名序列“NAMES…”中取出非目录部分。目录部分是指最后一个斜线(“/”)(包括斜线)之前的部分。删除所有文件名中的目录部分,只保留非目录部分。
返 回 值:文件名序列“NAMES…”中每一个文件的非目录部分。
函数说明:如果“NAMES…”中存在不包含斜线的文件名,则不改变这个文件名。以反斜线结尾的文件名,是用空串代替,因此当“NAMES…”中存在多个这样的文件名时,返回结果中分割各个文件名的空格数目将不确定!这是此函数的一个缺陷。
3.$(suffix NAMES…)
函数名称:取后缀函数—suffix。
函数功能:从文件名序列“NAMES…”中取出各个文件名的后缀。后缀是文件名中最后一个以点“.”开始的(包含点号)部分,如果文件名中不包含一个点号,则为空。
返 回 值:以空格分割的文件名序列“NAMES…”中每一个文件的后缀序列。
函数说明:“NAMES…”是多个文件名时,返回值是多个以空格分割的单词序列。如果文件名没有后缀部分,则返回空。
4.$(basename NAMES…)
函数名称:取前缀函数—basename。
函数功能:从文件名序列“NAMES…”中取出各个文件名的前缀部分(点号之后的部分)。前缀部分指的是文件名中最后一个点号之前的部分。
返 回 值:空格分割的文件名序列“NAMES…”中各个文件的前缀序列。如果文件没有前缀,则返回空字串。
函数说明:如果“NAMES…”中包含没有后缀的文件名,此文件名不改变。如果一个文件名中存在多个点号,则返回值为此文件名的最后一个点号之前的文件名部分。
5.$(addsuffix SUFFIX,NAMES…)
函数名称:加后缀函数—addsuffix。
函数功能:为“NAMES…”中的每一个文件名添加后缀“SUFFIX”。参数“NAMES…”为空格分割的文件名序列,将“SUFFIX”追加到此序列的每一个文件名的末尾。
返 回 值:以单空格分割的添加了后缀“SUFFIX”的文件名序列。
6.$(addprefix PREFIX,NAMES…)
函数名称:加前缀函数—addprefix。
函数功能:为“NAMES…”中的每一个文件名添加前缀“PREFIX”。参数“NAMES…”是空格分割的文件名序列,将“SUFFIX”添加到此序列的每一个文件名之前。
返 回 值:以单空格分割的添加了前缀“PREFIX”的文件名序列。
7.$(join LIST1,LIST2)
函数名称:单词连接函数——join。
函数功能:将字串“LIST1”和字串“LIST2”各单词进行对应连接。就是将“LIST2”中的第一个单词追加“LIST1”第一个单词字后合并为一个单词;将“LIST2”中的第二个单词追加到“LIST1”的第一个单词之后并合并为一个单词,……依次列推。
返 回 值:单空格分割的合并后的字(文件名)序列。
函数说明:如果“LIST1”和“LIST2”中的字数目不一致时,两者中多余部分将被作为返回序列的一部分。
8.$(wildcard PATTERN)
函数名称:获取匹配模式文件名函数—wildcard
函数功能:列出当前目录下所有符合模式“PATTERN”格式的文件名。
返 回 值:空格分割的、存在当前目录下的所有符合模式“PATTERN”的文件名。
函数说明:“PATTERN”使用shell可识别的通配符,包括“?”(单字符)、“*”(多字符)等。
三、其它函数
1.$(foreach VAR,LIST,TEXT)
函数功能:函数“foreach”不同于其它函数。它是一个循环函数。类似于Linux的shell中的循环(for语句)。这个函数的工作过程是这样的:如果必要(存在变量或者函数的引用),首先展开变量“VAR”和“LIST”;而表达式“TEXT”中的变量引用不被展开。执行时把“LIST”中使用空格分割的单词依次取出赋值给变量“VAR”,然后执行“TEXT”表达式。重复直到“LIST”的最后一个单词(为空时结束)。“TEXT”中的变量或者函数引用在执行时才被展开,因此如果在“TEXT”中存在对“VAR”的引用,那么“VAR”的值在每一次展开式将会到的不同的值。
返 回 值:空格分割的多次表达式“TEXT”的计算的结果。
2.$(if CONDITION,THEN-PART[,ELSE-PART])
函数功能:函数“if”提供了一个在函数上下文中实现条件判断的功能。就像make所支持的条件语句—ifeq。第一个参数“CONDITION”,在函数执行时忽略其前导和结尾空字符并展开。“CONDITION”的展开结果非空,则条件为真,就将第二个参数“THEN_PATR”作为函数的计算表达式,函数的返回值就是第二表达式的计算结果;“CONDITION”的展开结果为空,将第三个参数“ELSE-PART”作为函数的表达式,返回结果为第三个表达式的计算结果。
返 回 值:根据条件决定函数的返回值是第一个或者第二个参数表达式的计算结果。当不存在第三个参数“ELSE-PART”,并且“CONDITION”展开为空,函数返回空。
函数说明:函数的条件表达式“CONDITION”决定了,函数的返回值只能是“THEN-PART”或者“ELSE-PART”两个之一的计算结果。
3.$(call VARIABLE,PARAM,PARAM,...)
函数功能:“call”函数是唯一一个可以创建定制参数化的函数的引用函数。我们可以将一个变量定义为一个复杂的表达式,用“call”函数根据不同的参数对它进行展开来获得不同的结果。在执行时,将它的参数“PARAM”依次赋值给临时变量“$(1)”、“$(2)”(这些临时变量定义在“VARIABLE”的值中,参考下边的例子)……call函数对参数的数目没有限制,也可以没有参数值,没有参数值的“call”没有任何实际存在的意义。执行时变量“VARIABLE”被展开为在函数上下文有效的临时变量,变量定义中的“$(1)”作为第一个参数,并将函数参数值中的第一个参数赋值给它;变量中的“$(2)”一样被赋值为函数的第二个参数值;依此类推(变量$(0)代表变量“VARIABLE”本身)。之后对变量“VARIABLE” 表达式的计算值。
返 回 值:参数值“PARAM”依次替换“$(1)”、“$(2)”…… 之后变量“VARIABLE”定义的表达式的计算值。
函数说明:1.函数中“VARIBLE”是一个变量名,而不是对变量的引用。因此,通常“call”函数中的“VARIABLE”中不包含“$”(当然,除了此变量名是一个计算的变量名)。2.
当变量“VARIBLE”是一个make内嵌的函数名时(如“if”、“foreach”、“strip”等),对“PARAM”参数的使用需要注意,因为不合适或者不正确的参数将会导致函数的返回值难以预料。3. 函数中多个“PARAM”之间使用逗号分割。4.变量“VARIABLE”在定义时不能定义为直接展开式!只能定义为递归展开式。
4.value函数
$(value VARIABLE)
函数功能:不对变量“VARIBLE”进行任何展开操作,直接返回变量“VARIBALE”代表的值。这里“VARIABLE”是一个变量名,一般不包含“$”(当然,除了计算的变量名),
返 回 值:变量“VARIBALE”所定义文本值(不展开其中的变量或者函数应用)。
5.eval函数
函数功能:函数“eval”是一个比较特殊的函数。使用它我们可以在我们的Makefile中构造一个可变的规则结构关系(依赖关系链),其中可以使用其它变量和函数。函数“eval”对它的参数进行展开,展开的结果作为Makefile的一部分,make可以对展开内容进行语法解析。展开的结果可以包含一个新变量、目标、隐含规则或者是明确规则等。也就是说此函数的功能主要是:根据其参数的关系、结构,对它们进行替换展开。
返 回 值:函数“eval”的返回值时空,也可以说没有返回值。
函数说明:“eval”函数执行时会对它的参数进行两次展开。第一次展开过程发是由函数本身完成的,第二次是函数展开后的结果被作为Makefile内容时由make解析时展开的。明确这一点对于使用“eval”函数非常重要。在理解了函数“eval”二次展开的过程后。实际使用时,当函数的展开结果中存在引用(格式为:$(x))时,那么在函数的参数中应该使用“$$”来代替“$”。因为这一点,所以通常它的参数中会使用函数“value”来取一个变量的文本值。
6.origin函数
$(origin VARIABLE)
函数功能:函数“origin”查询参数“VARIABLE”(通常是一个变量名)的出处。
函数说明:“VARIABLE”是一个变量名而不是一个变量的引用。因此通常它不包含“$”(当然,计算的变量名例外)。
返 回 值:返回“VARIABLE”的定义方式。用字符串表示。
. undefined
变量“VARIABLE”没有被定义。
. default
变量“VARIABLE”是一个默认定义(内嵌变量)。如“CC”、“MAKE”、“RM”等变量。如果在Makefile中重新定义这些变量,函数返回值将相应发生变化。
. environment
变量“VARIABLE”是一个系统环境变量,并且make没有使用命令行选项“-e”(Makefile中不存在同名的变量定义,此变量没有被替代)。
. environment override
变量“VARIABLE”是一个系统环境变量,并且make使用了命令行选项“-e”。Makefile中存在一个同名的变量定义,使用“make -e”时环境变量值替代了文件中的变量定义。
. file
变量“VARIABLE”在某一个makefile文件中定义。
. command line
变量“VARIABLE”在命令行中定义。
. override
变量“VARIABLE”在makefile文件中定义并使用“override”指示符声明。
. automatic
变量“VARIABLE”是自动化变量。
7.shell函数
不同于除“wildcard”函数之外的其它函数。make可以使用它来和外部通信。
函数功能:函数“shell”所实现的功能和shell中的引用(``)相同。实现了命令的扩展。意味着需要一个shell命令作为它的参数,而返回的结果是此命令在shell中的执行结果。make仅仅对它的回返结果进行处理;make将函数的返回结果中的所有换行符(“\n”)或者一对“\n\r”替换为单空格;并去掉末尾的回车符号(“\n”)或者“\n\r”。函数展开式时,它所调用的命令(它的参数)得到执行。除了对它的引用出现在规则的命令行中和递归的变量定义引用以外,其它决大多数情况下,make在读取Makefile时函数shell就被扩展。
返 回 值:函数“shell”的参数在shell中的执行结果。
函数说明:函数本身的返回值是其参数的执行结果,没有进行任何处理。对结果的处理是由make进行的。当对函数的引用出现在规则的命令行中,命令行在执行时函数引用才被展开。展开过程函数参数的执行时在另外一个shell进程中完成的,因此对于出现在规则命令行的多级“shell”函数引用需要谨慎处理,否则会影响效率(每一级的“shell”函数的参数都会有各自的shell进程)。
8.error 函数
$(error TEXT…)
函数功能:产生致命错误,并提示“TEXT…”信息给用户,之后退出make的执行。需要说明的是:“error”函数是在函数展开式(函数被调用时)才提示信息并结束make进程。因此如果函数出现在命令中或者一个递归的变量定义中时,在读取Makefile时不会出现错误。而只有包含“error”函数引用的命令被执行,或者定义中引用此函数的递归变量被展开时,才会提示致命信息“TEXT…”同时make退出执行。
返 回 值:空字符
函数说明:“error”函数一般不出现在直接展开式的变量定义中,否则在make读取Makefile时将会提示致命错误。
9. warning 函数
$(warning TEXT…)
函数功能:函数“warning”类似于函数“error”,区别在于它不会导致致命错误(make不退出),而只是提示“TEXT…”,make的执行过程继续。
返 回 值:空字符
函数说明:用法和“error”类似,展开过程相同。
函数的调用语法
函数调用,很像变量的使用,也是以“$”来标识的,其语法如下:
$(
)
或是
${ }
这里,就是函数名,make支持的函数不多。是函数的参数,参数
间以逗号“,”分隔,而函数名和参数之间以“空格”分隔。函数调用以“$”开头,以圆
括号或花括号把函数名和参数括起。感觉很像一个变量,是不是?函数中的参数可以使
用变量,为了风格的统一,函数和变量的括号最好一样,如使用“$(substa,b,$(x))”这
样的形式,而不是“$(substa,b,${x})”的形式。因为统一会更清楚,也会减少一些不必
要的麻烦。
还是来看一个示例:
comma:= ,
empty:=
space:= $(empty) $(empty)
foo:= a b c
bar:= $(subst $(space),$(comma),$(foo))
在这个示例中,$(comma)的值是一个逗号。$(space)使用了$(empty)定义了一个空格,
$(foo)的值是“a b c”,$(bar)的定义用,调用了函数“subst”,这是一个替换函数,这
个函数有三个参数,第一个参数是被替换字串,第二个参数是替换字串,第三个参数
是替换操作作用的字串。这个函数也就是把$(foo)中的空格替换成逗号,所以$(bar)的值
是“a,b,c”。
文件名操作函数
下面我们要介绍的函数主要是处理文件名的。每个函数的参数字符串都会被当做一个或
是一系列的文件名来对待。
$(dir
)
名称:取目录函数——dir。
功能:从文件名序列中取出目录部分。目录部分是指最后一个反斜杠(“/”)
之前的部分。如果没有反斜杠,那么返回“./”。
返回:返回文件名序列的目录部分。
示例:$(dirsrc/foo.chacks)返回值是“src/./”。
$(notdir )
名称:取文件函数——notdir。
功能:从文件名序列中取出非目录部分。非目录部分是指最后一个反斜杠(“/
”)之后的部分。
返回:返回文件名序列的非目录部分。
示例:$(notdirsrc/foo.chacks)返回值是“foo.chacks”。
$(suffix )
名称:取后缀函数——suffix。
功能:从文件名序列中取出各个文件名的后缀。
返回:返回文件名序列的后缀序列,如果文件没有后缀,则返回空字串。
示例:$(suffixsrc/foo.csrc-1.0/bar.chacks)返回值是“.c.c”。
$(basename )
名称:取前缀函数——basename。
功能:从文件名序列中取出各个文件名的前缀部分。
返回:返回文件名序列的前缀序列,如果文件没有前缀,则返回空字串。
示例:$(basenamesrc/foo.csrc-1.0/bar.chacks)返回值是“src/foosrc-1.0/barhacks”。
$(addsuffix , )
名称:加后缀函数——addsuffix。
功能:把后缀加到中的每个单词后面。
返回:返回加过后缀的文件名序列。
示例:$(addsuffix.c,foobar)返回值是“foo.cbar.c”。
$(addprefix , )
名称:加前缀函数——addprefix。
功能:把前缀加到中的每个单词后面。
返回:返回加过前缀的文件名序列。
示例:$(addprefixsrc/,foobar)返回值是“src/foosrc/bar”。
$(join , )
名称:连接函数——join。
功能:把中的单词对应地加到的单词后面。如果的单词个数要比
的多,那么,中的多出来的单词将保持原样。如果的单词个数要比
多,那么,多出来的单词将被复制到中。
返回:返回连接过后的字符串。
示例:$(joinaaabbb,111222333)返回值是“aaa111bbb222333”。
foreach函数
foreach 函数和别的函数非常的不一样。因为这个函数是用来做循环用的,Makefile 中的
foreach 函数几乎是仿照于 Unix 标准 Shell(/bin/sh)中的 for 语句,或是 C-Shell
(/bin/csh)中的foreach语句而构建的。它的语法是:
$(foreach ,, )
这个函数的意思是,把参数中的单词逐一取出放到参数所指定的变量中,
然后再执行所包含的表达式。每一次会返回一个字符串,循环过程中,
的所返回的每个字符串会以空格分隔,最后当整个循环结束时,所返回的
每个字符串所组成的整个字符串(以空格分隔)将会是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中的参数是一个临时的局部变量,foreach函数执行完后,参数
的变量将不在作用,其作用域只在 foreach 函数当中。
if函数
if 函数很像 GNU 的 make 所支持的条件语句——ifeq(参见前面所述的章节),if 函数
的语法是:
$(if , )
或是
$(if ,, )
可见,if函数可以包含“else”部分,或是不含。即if函数的参数可以是两个,也可以是
三个。参数是if的表达式,如果其返回的为非空字符串,那么这个表达式就
相当于返回真,于是,会被计算,否则会被计算。
而if函数的返回值是,如果为真(非空字符串),那个会是整
个函数的返回值,如果为假(空字符串),那么会是整个函数的
返回值,此时如果没有被定义,那么,整个函数返回空字串。
所以,和只会有一个被计算。
call函数
call 函数是唯一一个可以用来创建新的参数化的函数。你可以写一个非常复杂的表达式,
这个表达式中,你可以定义许多参数,然后你可以用call函数来向这个表达式传递参
数。其语法是:
$(call
,,,...)
当make执行这个函数时,参数中的变量,如$(1),$(2),$(3)等,会被参
数,,依次取代。而的返回值就是call函数的返
回值。例如:
reverse = $(1) $(2)
foo = $(call reverse,a,b)
那么,foo的值就是“ab”。当然,参数的次序是可以自定义的,不一定是顺序的,如:
reverse = $(2) $(1)
foo = $(call reverse,a,b)
此时的foo的值就是“ba”。
origin函数
origin 函数不像其它的函数,他并不操作变量的值,他只是告诉你你的这个变量是哪里
来的?其语法是:
$(origin )
注意,是变量的名字,不应该是引用。所以你最好不要在中使用“
$”字符。Origin 函数会以其返回值来告诉你这个变量的“出生情况”,下面,是 origin
函数的返回值:
“undefined”
如果从来没有定义过,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函数把执行操作系统命令后的输出作为函数
返回。于是,我们可以用操作系统命令以及字符串处理命令awk,sed等等命令来生成
一个变量,如:
contents := $(shell cat foo)
files := $(shell echo *.c)
注意,这个函数会新生成一个Shell程序来执行命令,所以你要注意其运行性能,如果
你的Makefile中有一些比较复杂的规则,并大量使用了这个函数,那么对于你的系统
性能是有害的。特别是Makefile的隐晦的规则可能会让你的shell函数执行的次数比你
想像的多得多。