函数
GNUmake支持内置函数和用户自定义函数。函数调用看起来像是变量引用,只不过多了用逗号隔开的参数而已。所有的函数都具有相同的形式:$(function-namearg1[, argn])$之后是函数的名称,接着是函数的参数,参数之间以逗号隔开。
内置函数
内置函数是内嵌于make程序内的函数,可以直接使用。
字符串函数
$(filterpattern ..., text)
filter函数将text视为一系列以空格隔开的单词,与pattern比较之后,返回符合的单词(模式必须与单词相匹配,而不能只匹配一部分)。模式可以有多个,只要符合其中一个就会被匹配。模式中采用%作为通配符,当有多个%出现在一个模式中,只有第一个作为通配符,其他的作为字面值。
$(filter-outpattern ..., text)
filter-out函数刚好与filter相反,用来选出与模式不相符的每个单词。
text = apple pear banana watermelon orange pineapple
filtered = $(filter %apple pear %ge,$(text))
not_filtered = $(filter-out %apple pear %.ge, $(text))
all :
@echo $(filtered)
@echo $(not_filtered)
$ make
apple pear orange pineapple
banana watermelon orange
$(findstringstring...,text)
此函数将会从text里搜索string。如果找到了就返回该字符串,否则返回空string没有模式匹配功能。
$(substsearch-string,replace-string,text)
这是一个不具有模式匹配的搜索替换函数。search-string和replace-string不必是整个单词。
$(patsubstsearch-string,replace-string,text)
这个替换函数具有模式匹配功能。同样的,只能用一个%。
sources = hello.c lib.c main.c tom_hello.c tom_lib.c
objects = $(subst .c,.o, $(sources))
has_main.c = $(findstring main.c, $(sources))
has_main = $(findstring main, $(sources))
no_domain = $(findstring domain, $(sources))
patsubsted = $(patsubst tom%,jerry%, $(sources))
all:
@echo $(objects)
@echo $(has_main.c)
@echo $(has_main)
@echo $(no_domain)
@echo $(patsubsted)
$ make
hello.o lib.o main.o tom_hello.o tom_lib.o
main.c
main
hello.c lib.c main.c jerry_hello.c jerry_lib.c
$(wordstext)
此函数返回text中单词的数量。
$(wordn,text)
此函数返回text中的第n个单词。第一个单词编号为1,如果n的值大于单词的总数,返回空值。
$(firstwordtext)
返回text中的第一个单词。等效与$(word 1,text)。
$(wordliststart,end,text)
此函数返回text中范围从start(含)到end(含)的单词。
$(sortlist)
sort函数会排序它的list参数并且移除重复的单词。此函数会返回按照字典顺序的不重复的单词列表,以空格分隔。而且,sort还会删除前导和结尾的空格。这里的sort是make内部实现的函数,不是shell里的程序。
$(shellcommand)
shell的参数会被扩展(就像所有其他参数)并且传递给subshell执行。然后make读取command的标准输出,并将之作为函数的返回值。输出中所出现的一系列换行符会被缩减成单一的空格,任何末尾的换行被删除。标准错误并不会被返回。
$(wildcardpattern...)
wildcard的参数是一个模式列表,他会对每个模式进行扩展。如果扩展的模式找不到符合的文件,返回空字符串。该模式为shell的glob匹配。
如果想要判断某个文件是否存在,就可以使用wildcard:
dot-emacs-exists := $(wildcard ~/.emacs)
$(dirlist...)
dir函数返回list中每个单词的目录部分。
$(notdirname...)
返回每个单词的文件名部分。
$(suffixname...)
返回由每个单词的扩展名构成的单词列表
$(basenamename...)
返回由每个单词的非扩展名部分组成的单词列表
$(addsuffix,suffix,name...)
返回由name单词列表中的每个单词前加上suffix前缀构成的新的单词表。
$(addprefix,prefix,name...)$(joinprefix-list,suffix-list)
join函数把prefix-list的第i个单词与suffix-list的第i个单词连在一起构成新序列的第i个单词。
流程控制函数
$(ifcondition,then-part,else-part)
if函数(可不是条件指令ifne,ifeq,ifdef等)会根据条件表达式的求值结果,从两个宏中选择一个进行扩展。
如果condition扩展之后包含任何字符(包括空格),求值结果为真,会对then-part进行扩展;否则,如果condition扩展之后为空,会对else-part进行扩展。
make对condition求值时,首先会移除前导及末尾的空格。
$(errortext)
error函数会使make输出text错误信息和当前makefile的名称行号之后以2这个状态结束运行。
$(warntext)
与error类似,输出text的内容,但并不退出。扩展结果为空串。$(foreachvariable,list,body)
当foreach函数执行的时候,它将list中的每个单词作为body中的variable进行操作,返回操作的结果。
sources = fat32.c format.c alloca.c main.c
dirs = src bin inc
objects = $(foreach var,$(sources), $(subst .c,.o, $(var)))
full_path = $(foreach var, $(sources), $(addprefix src/, $(var)))
do_mkdirs = $(foreach var, $(dirs), $(shell mkdir -p $(var)))
all:
@echo $(objects)
@echo $(full_path)
@echo $(do_mkdirs)
$ make
fat32.o format.o alloca.o main.o
src/fat32.c src/format.c src/alloca.c src/main.c
#产生了三个文件夹
eval函数
$(evalcontents)
这个函数很重要。它用来将它后面的文本直接放入make解析器。
首先make会扫描eval的参数并对其中的变量进行扩展,然后make会解析文本进行求值的动作(这里也包含了一次扩展动作,因为普通的在makefile中的文本也会扩展一次),就好像它是输入的文本一样。
eval函数经常用与含有多行文本的宏的展开。一个解析器顶层的宏被扩展成多行文本是不合法的,但是用eval函数可以将展开后的宏直接当做输入的文本,再展开一次之后就放入数据库中了。而eval函数本身的展开结果为空。
注意:定义复杂的宏时要考虑二次展开的问题,然后用eval函数引用这个宏。
用户自定义函数
可以用define定义一个自定义的宏:
define macor-name
contents
endef
用户自定义函数是带有参数的宏,宏定义中的$1、$2...是函数的形参,宏的定义就是函数的定义。
调用一个自定义函数的形式是:
$(callmacro-name[,param1 ...])。
call是一个内置函数,call扩展它的第一个参数并把其他参数依次替换到宏定义中的$1、$2...的地方。macro-name之后是宏的参数,以逗号隔开。在函数的内部可以使用$0来访问函数名。
call的参数传递机制很简单。调用时可以为call指定任意个参数。如果宏定义内引用了$n,但是调用时并未指定相应的参数,那么该变量就为空值。如果call的参数比宏的$n引用还多,则被忽略。
注意使用函数是不要随意加前导空格,否则可能回产生难以排查的错误。(但降低了可读性)

本文详细介绍了GNU Make内置函数和用户自定义函数的功能与用法,包括字符串处理、流程控制、文件路径操作等功能,帮助读者深入理解Makefile的编写技巧。
514

被折叠的 条评论
为什么被折叠?



