函数的调用语法
- 函数使用“$”调用:
$(function arguments)
${function arguments}
例如:
$(subst .c, .o, test1.c test2.c)
还是来看一个示例:
#$(comma)值是一个逗号
comma= ,
$(empty)值是空
empty=
$(space)值是空格, 如果直接赋值空格会被忽略,这里巧妙的使用空变量$(empty)
space= $(empty) $(empty)
foo= a b c
#$(comma)和$(foo)紧跟‘,’不能有空格,否则结果不正确,也不能使用双引号
#$(bar)的值为 a,b,c
bar= $(subst $(space),$(comma),$(foo))
subset是一个替换函数,参数1是搜索的子字串,参数2是被替换子字串,参数3
是执行替换操作的字符串。$(bar)的值 a,b,c。
常用字符串函数介绍
- subst
功能:字符串替换
示例:
#目标字符串中的ee变成大写的EE
$(subst ee,EE,feet on the street)
- patsubst
功能:字符串替换,支持通配符
示例:
#符合模式[%.c]的子串替换成[%.o], 返回“x.c.obar.o”,贪婪匹配
$(patsubst %.c,%.o,x.c.c bar.c)
与变量的替换功能相似,例如:
#定义变量objects
objects=foo.o bar.o baz.o
#.o会被替换成.c,
$(objects:.o=.c)
- strip
功能:将字符串中多个空格变成一个空格
示例:
data =" a b c "
#data1没有使用双引号,a前的空格和c后空格都会被忽略
data1= a b c
dataprint:
#输出“ a b c ”,c之后还有一个空格
@echo $(strip $(data))
输出“a b c”
@echo $(strip $(data1))
- findstring
功能:在字符串中查找子串。
返回:如果找到,返回,否则返回空字符串。
示例:
#返回a
$(findstring a,a b c)
#返回空串
$(findstring a,b c)
- filter
功能:在字符串中查找子串。
返回:如果找到符合模式子串,返回子串,否则返回空串。
示例:
sources= foo.c foo.h bar.s
foo: $(sources)
#返回“foo.c bar.s”
cc $(filter %.c %.s,$(sources)) -o foo
- filter-out
功能:符合模式的被删除,保留不符合模式的子串。
返回:符合模式的被删除,保留不符合模式的子串。
示例:
objects=main1.o foo.o main2.o bar.o
mains=main1.o main2.o
#返回值是“foo.o bar.o”。
$(filter-out $(mains),$(objects))
- sort
功能:给字符串中的单词排序(升序)。
返回:返回排序后的字符串,去除重复字符串。
示例:
#输出“bar foo lose”
@echo $(sort foo lose foo bar)
- word
函数功能:取字串“TEXT”中第“N”个单词(“N”的值从 1开始)。
返回值:返回字串“TEXT”中第“N”个单词。
函数说明:如果“N”值大于“TEXT”中单词的数目,返回空串。如果“N”为 0,出错!
示例:
#返回值为“bar”
$(word 2, foo bar baz)
- wordlist
$(wordlist S,E,TEXT)
函数功能:从字串“TEXT”中取出从“S”开始到“E”的单词串。 “S”和“E”表示单词在字串中位 置的数字。
返回值:字串“TEXT”中从第“S”到“E”(包括“E”)的单词字串。
函数说明:“S”和“E”都是从1开始的数字。 当“S”比“TEXT”中的字数大时,返回空。如果“E”大于“TEXT”字数,返回从“S”开始,到“TEXT”结束的单词串。如果“S”大于“E”,返回空。
示例:
#返回值为:“bar baz”。
$(wordlist 2, 3, foo bar baz)
- words
功能:统计字符串包含的单词个数
示例:
#返回值为:4。
$(words foo bar foo baz)
- firstword
功能:去字符串的首个单词。
示例:
#返回值为:foo 。
$(firstword foo bar foo baz)
- 综合示例
make使用“VPATH”变量来指定“依赖文件”的搜索路径。于是,我们可以利用这个搜索路径来指定编译器对头文件的搜索路径参数CFLAGS,如:
override CFLAGS += $(patsubst %,-I%,$(subst :, ,$(VPATH)))
如果我们的“$(VPATH)”值是“include:../common”,经过函数处理后将返回“-Iinclude -I../common”,这正是搜索头文件路径的参数。
文件名操作函数
下面我们要介绍的函数主要是处理文件名的。每个函数的参数字符串都会被当做一个或是一系列的文件名来对待。
- wildcard
作用:寻找文件
功能:寻找指定模式的文件,返回成以空格隔开的一整行字符
示例:
$(wildcard *.c)
- dir
名称:取目录函数。
功能:从文件名序列中取出目录部分。目录部分是指最后一个反斜杠(“/”)之前的部分。如果没有反斜杠,那么返回“./”。
返回:返回文件名序列的目录部分。
示例:
#返回值是“src/ ./”。
$(dir src/foo.c hacks)
- notdir
名称:取文件函数。
功能:从文件名序列中取出非目录部分。非目录部分是指最后一个反斜杠(“/”)之后的部分。
返回:返回文件名序列的非目录部分。
示例:
#返回值是“foo.c hacks”。
$(notdir src/foo.c hacks)
- suffix
名称:取后缀函数——suffix。
功能:从文件名序列中取出各个文件名的后缀。
返回:返回文件名序列的后缀序列,如果文件没有后缀,则返回空字串。
示例:
#返回值是“.c .c”。
$(suffix src/foo.c src-1.0/bar.c hacks)
- basename
名称:取前缀函数——basename。
功能:从文件名序列中取出各个文件名的前缀部分。
返回:返回文件名序列的前缀序列,如果文件没有前缀,则返回空字串。
示例:
#返回值是“src/foo src-1.0/bar hacks”。
$(basename src/foo.c src-1.0/bar.c hacks)
- addsuffix
名称:加后缀函数。
功能:把后缀加到中的每个单词后面。
返回:返回加过后缀的文件名序列。
示例:
#返回值是“foo.c bar.c”。
$(addsuffix .c,foo bar)
- addprefix
名称:加前缀函数。
功能:把前缀加到中的每个单词后面。
返回:返回加过前缀的文件名序列。
示例:
#返回值是“src/foo src/bar”。
$(addprefix src/,foo bar)
- join
名称:连接函数。
功能:把中的单词对应地加到的单词后面。如果的单词个数要比的多,那么,中的多出来的单词将保持原样。如果的单词个数要比多,那么,多出来的单词将被复制到中。
返回:返回连接过后的字符串。
示例:
#返回aaa111 bbb222 ccc333
@echo $(join aaa bbb ccc,111 222 333)
#返回aaa111 bbb222 333
@echo $(join aaa bbb,111 222 333)
#返回aaa111 bbb222 ccc
@echo $(join aaa bbb ccc,111 222)
- foreach函数
名称:foreach 函数用来执行循环的,语法类似shell脚本中for语句。
功能:把参数中的单词逐一取出放到参数所指定的变量中,然后再执行
示例:
#输出值“a.o b.o c.o d.o”
files := $(foreach n,$(names),$(n).o)
$(name)中的单词会被挨个取出,并存到变量“n”中,“$(n).o”每次根据“$(n)”计算出一个值,这些值以空格分隔作为函数的返回值。注意,foreach中的参数是一个临时的局部变量,foreach函数执行完后,参数的变量将不在作用,其作用域只在 foreach 函数当中。
- if函数
语法:$(if CONDITION,THEN-PART[,ELSE-PART])
功能:第一个参数“CONDITION” ,在函数执行时忽略其前导和结尾空字符,如果包含对其他变量或者函数的引用则进行展开。如果“CONDITION”的展开结果非空,则条件为真,就将第二个参数“THEN_PATR”作为函数的计算表达式;“CONDITION”的展开结果为空,将第三个参数“ELSE-PART”作为函数的表达式,函数的返回结果为有效表达式的计算结果。
返回值:根据条件决定函数的返回值是第一个或者第二个参数表达式的计算结果。当不存在第三个参数“ELSE-PART” ,并且“CONDITION”展开为空,函数返回空。
函数说明:函数的条件表达式“CONDITION”决定了函数的返回值只能是“THEN-PART”或者“ELSE-PART”两个之一的计算结果。
示例:
SUBDIR += $(if $(SRC_DIR),$(SRC_DIR),/home/src)
函数的结果是:如果“SRC_DIR”变量值不为空,则将变量“SRC_DIR”指定的目录作为一个子目录;否则将目录“/home/src”作为一个子目录。
- call函数
call函数用来调用非常复杂的表达式,同时向表达式中传递参数。
语法:$(call <expression>,<parm1>,<parm2>,<parm3>,...)
功能:这个call函数时<expression>中的参数(如$(1),$(2),$(3)等)会被参数< parm1>,<parm2>,<parm3>依次取代。而<expression>的返回值就是 call函数的返回值。
注意:
1. call函数中对VARIABLE的调用,直接给函数或变量名就好了,不要用"$";
2. 多个PARAM使用逗号分割开,且逗号和PARAM之间不能有空格,否则会导致解析异常;
示例1:
define FUNC1
$(info echo 1-"hello")
endef
define FUNC2
$(info echo 2-$(1) $(2))
endef
$(call FUNC1)
$(call FUNC2,hello,world)
$(call FUNC2, hello, world)
all:
@echo Done
输出:
echo 1-"hello"
echo 2-hello world
echo 2- hello world
Done
示例2
VARIABLE1 := $(2) $(1) #立即赋值变量值为0
VARIABLE2 = $(2) $(1) #递归赋值
call-test:
输出:
#输出为空
@echo $(call VARIABLE1,hello,world)
#输出 b,a
@echo $(call VARIABLE2 ,a,b)
- origin函数
语法:$(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函数执行的次数比你想像的多得多。