Makefile中,函数调用的格式如下:
$(function args)
这里function
是函数名,args
是该函数的参数。
参数和函数名之间是用空格或 Tab 隔开,如果有多个参数,它们之间用逗号隔开。这些空格和逗号不是参数值的一部分。
Makefile 的实际运用中会使用大量的函数,现在介绍一些常用的。
1、$(join $(list1), $(list2))
把两个列表中的相同位置的元素连接起来,合并为一个新的列表joined_list
比如有以下两个列表
list1 := a b c
list2 := 1 2 3
那么此时执行
joined_list := $(join $(list1),$(list2))
会返回新列表为
//输出的结果为: a 1 b 2 c 3
$(info $(joined_list))
如果列表的长度不同列表长度不同,那么会忽略多余的元素.
例如:
list1 := a b c
list2 := 1 2
joined_list := $(join $(list1),$(list2))
则此时执行
//此时输出的结果为: a 1 b 2
$(info $(joined_list))
最后,$(join $(list1),$(list2))
该函数也支持三个列表,多个列表,同理可得,若
list1 := a b c
list2 := 1 2 3
list3 := x y z
joined_list := $(join $(list1),$(list2),$(list3))
//输出为 a 1 x b 2 y c 3 z
$(info $(joined_list))
此外,在Makefile中,$(join [1,2,3],[4,5,6])
不是一个有效的语法。Makefile中的函数参数需要使用变量或者变量的引用,而不是直接使用列表。
2、$(wildcard pattern)
用于匹配指定模式的而文件列表。
1、具体来说,它会返回一个包含所有匹配文件名的列表(包括文件路径),这些文件名之间用空格分开。
2、模式可以包含通配符,如*(表示匹配任意长度的任意字符)和?(表示匹配任意单个字符)等,用于匹配文件名中的字符。
例如,*.txt表示匹配指定路径下左右以.txt结尾的文件,
file?.txt表示匹配所有文件名为fileX.txt(其中X是任意单个字符)的文件。
该函数的使用举例,若所指定的目录下有以下是个文件:
file1.txt file2.ini image.jpg test.txt script.js
file := $(wildcard *.txt)
//输出当前目录下的所有以.txt结尾的文件
//输出结果为: file1.txt test.txt
$(info $(file))
//匹配指定路径$(path)下的所有以.txt结尾的文件,
//file1.txt file2.ini image.jpg test.txt script.js
file := $(wildcard $(path)/*.txt)
//输出指定路径$(path)下的所有以.txt结尾的文件,
//输出结果为: $(path)/file1.txt $(path)/test.txt
$(info $(file))
$(wildcard pattern)
函数只能获取当前目录下的文件列表,不能递归获取子目录中的文件。
如果需要获取子目录中的文件列表,可以使用$(shell find ...)
命令或者其他递归查找文件的工具。
3、$(notdir names)
函数会将给定的路径列表names中的每个路径都解析为文件名,并返回一个新的列表(只要有文件名),其中包含所有文件名,用空格分开
例如:
path := /path/to/file1.txt /path/to/file2.txt /another/path/file3.txt
//将路径列表paths中的每个路径都解析为文件名,并返回一个新的列表files
files := $(notdir $(path))
//输出结果为: file1.txt file2.txt file3.txt
$(info $(files))
4、$(patsubst pattern,replacement,text)
用于替换文本中匹配某个模式的部分。
具体来说,会在文本text中查找与给定模式pattern匹配的部分,(其中pattern可以使用通配符%来匹配任意长度的任意字符),并将其替换为replacement,它返回替换后的新文本。
例如:
text := src/file1.cpp src/file2.cpp res/file3.xml file4.cpp
replace_txt := $(patsubst src/%.cpp,obj/%.o,$(text))
//输出结果为: obj/file1.o obj/file2.o
$(info $(replace_txt))
text := src/file1.cpp src/file2.cpp res/file3.xml file4.cpp
replace_txt := $(patsubst src/%.cpp,obj/%.o,$(filter src/%.cpp,$(text)))
$(patsubst res/%.xml,obj/%.o,$(filter res/%.xml,$(text)))
$(filter-out src/%.cpp res/%.xml,$(text))
//$(patsubst src/%.cpp,obj/%.o,$(filter src/%.cpp,$(text))) 用filter过滤出text中
//以"src/"开头,".cpp"结尾的文件,把它修改为以"obj/"开头,".o"结尾的文件
//$(filter-out)函数过滤出不匹配任何模式的部分,即"file4.cpp"
//输出结果为: obj/file1.o obj/file2.o obj/file3.o file4.cpp
$(info $(replace_txt))
最后,根据以上介绍,写一个是运用中可使用到的Makefile语句,作用是拷贝文件到指定目录。如下:
//其中,$(LOCAL_PATH)/base/common/files/目录下的文件为
//test1.txt test2.txt
RODUCT_COPY_FILES += \
$(join $(wildcard $(LOCAL_PATH)/base/common/files/*), $(patsubst %,:path/text/%,$(notdir $(wildcard $(LOCAL_PATH)/base/common/files/*))))
//最后该语句的结果为得到一个字符串为:
//$(LOCAL_PATH)/base/common/files/test1.txt:path/text/test1.txt $(LOCAL_PATH)/base/common/files/test2.txt:path/text/test2.txt
接下来解析该语句
//这里通过$(wildcard pattern)函数输出$(LOCAL_PATH)/base/common/files路径下的所有文件
//返回 $(LOCAL_PATH)/base/common/files/test1.txt $(LOCAL_PATH)/base/common/files/test2.txt
$(wildcard $(LOCAL_PATH)/base/common/files/*)
//这里通过$(notdir names)函数输出 $(wildcard $(LOCAL_PATH)/base/common/files/*) 返回的文件列表的所有文件名
//返回 test1.txt test2.txt
$(notdir $(wildcard $(LOCAL_PATH)/base/common/files/*))
//这里通过$(patsubst pattern,replace,txt)把$(notdir $(wildcard $(LOCAL_PATH)/base/common/files/*))返回的内容 替换为以:path/text/开头
//返回为: :path/text/test1.txt :path/text/test2.txt
$(patsubst %,:path/text/%,$(notdir $(wildcard $(LOCAL_PATH)/base/common/files/*)))
//通过$(join $(list1),$(list2))合并 返回一个新的字符串
//返回为:$(LOCAL_PATH)/base/common/files/test1.txt:path/text/test1.txt $(LOCAL_PATH)/base/common/files/test2.txt:path/text/test2.txt
$(join $(wildcard $(LOCAL_PATH)/base/common/files/*), $(patsubst %,:path/text/%,$(notdir $(wildcard $(LOCAL_PATH)/base/common/files/*))))
这样就把这个字符串赋值给RODUCT_COPY_FILES
该语句的作用是 把$(LOCAL_PATH)/base/common/files/
的所有文件 拷贝到path/text/下
这个语句通常写在*.mk文件中,RODUCT_COPY_FILES
用于定义需要复制到系统镜像中的文件列表
$(join $(wildcard $(LOCAL_PATH)/base/common/files/*), $(patsubst %,:path/text/%,$(notdir $(wildcard $(LOCAL_PATH)/base/common/files/*))))
的结果会被追加到RODUCT_COPY_FILES
变量中,表示需要将这些文件复制到系统镜像中。
5、$(foreach var,list,text)
具体而言,$(foreach var, list, text)
函数会将列表list中的每个元素依次赋值给变量var,并根据每个元素生成一段文本text。然后,将所有生成的文本段连接在一起,并返回结果。
例子:
list := a.o c.o b.o
text := $(foreach f,$(list),.$(f).d)
//输出结果为: .a.o.d .c.o.d .b.o.d
$(info $(text))
6、$(subst from,to,text)
用"to"替换给定的"text"中的每个"from"。这个函数在Makefile中常用于替换文件路径、修改变量值等场景。
例子:
$(subst cats,dogs,I love cats and cats are cute)
//输出:I love dogs and dogs are cute
7、$(strip string)
去掉string中开头和结尾空格,并将中间的多个空格压缩为单个空格,并返回处理后的结果。
例子:
$(strip a b c )
//结果为: a b c
8、$(findstring find,in)
当我们需要判断某个变量中是否包含特定的字符串时,可以使用$(findstring)
函数。
具体来说,在字符串in
中搜寻find
,如果找到,则返回值是find
,否则返回值为空。
例子:
name := Joe Doe
ifeq($(findstring Doe,$(name)),Doe)
@echo "name中包含字符串Doe"
esle
@echo "name中不包含字符串Doe"
endif
9、$(sort list)
将list
中的字按字母顺序排序,并去掉重复的字。输出由单个空格隔开的字的列表.
举例来说,假设我们有一个变量files,其值为"file3 file1 file2 file3 file1",我们想要对files中的文件名进行排序并去重,可以使用$(sort)函数。
files := file3 file1 file2 file3 file1
//此时结果为:file1 file 2 file3
sorted_files := $(sort $(files))
$(sort foo bar lose)//输出:bar foo lose
10、$(dir names...)
在Makefile中,$(dir names)函数用于获取指定路径名中的目录部分。
具体而言:
files := dir1/file1 dir2/file2 dir3/file3
dirs := $(dir $(files))
//输出为:dir1/ dir2/ dir3/
11、$(suffix names...)
在Makefile中,$(suffix names...)
函数用于获取指定文件名中的后缀部分。
举例来说,假设我们有一个变量files,其值为"file1.c file2.cpp file3.txt",我们想要提取出这些文件名中的后缀部分,可以使用$(suffix)函数。
files := file1.c file2.cpp file3.txt
//输出为:.c .cpp .txt
sufiixes := $(suffix $(files))
12、$(basename names...)
在Makefile
中,$(basename names...)
函数用于获取指定文件名中的基本名称部分,即去除文件的后缀部分。
举例来说,假设我们有一个变量files,其值为file1.c src/file2.cpp file3
,我们想要获取这些文件名的基本名称部分,可以使用$(basename)
函数。
files := file1.c stc/file2.cpp file3
basenames := $(basename $(files))
//输出为:file1 src/file2 file3
13、$(addsuffix suffix,names...)
在Makefile中,$(addsuffix suffix,names...)
函数用于给指定的名称添加后缀。
举例来说,假设我们有一个变量files,其值为"file1 file2 file3",我们想要给这些文件名添加后缀".o",可以使用$(addsuffix)
函数。
files := file1 file2.mod src/file3
new_files := $(addsuffix .o,$(files))
//输出为: file1.o file2.mod.o src/file3.o
14、$(addprefix prefix,names...)
在Makefile
中,$(addprefix prefix,names...)
函数用于给指定的名称添加前缀,完成后将文件名串联起来,它们之间用单个空格隔开。
files := file1 file2 file3
new_files := $(addprefix src/,$(files))
//输出为: src/file1 src/file2 src/file3
15、$(foreach var,list,text)
在Makefile中,$(foreach var,list,text)
函数用于在循环中依次替换变量var,并执行指定的文本内容。前两个参数,var
和list
将首先扩展,注意最后一个参数‘text’此时不扩展;接着,list
扩展所得的每个字,都赋给var
变量;然后text
引用该变量进行扩展,因此text
每次扩展都不相同。
例子:
dirs : = a b c d
files := $(foreach dir,$(dirs),$(wildcard $(dirs)/*))
//最后为:file := $(wildcard a/* b/* c/* d/*),即返回a b c d目录下的所有文件
16、$(origin variable)
在Makefile中,$(origin variable)
函数用于获取变量的定义方式
foo := bar
all:
@echo "变量foo的定义方式: $(origin foo)"
执行make
后输出为
变量foo的定义方式: file
可以看到,变量foo的定义方式是file,表示该变量是通过文件或命令行参数定义的。
此外,返回值还有以下定义:
返回值 | 定义 |
---|---|
undefined | 如果变量 variable 从没有定义 |
default | 变量 variable 是缺省定义 |
environment | 变量 variable 作为环境变量定义,选项 -e 没有打开 |
environment override | 变量 variable 作为环境变量定义,选项 -e 已打开 |
file | 变量 variable 在命令行中定义 |
override | 变量 variable 在 Makefile 中用 override 指令定义 |
automatic | 变量 variable 是自动变量 |
17、$(shell command arguments)
在Makefile中,$(shell command arguments)
用于执行指定的shell命令,并返回其输出结果。
date := $(shell date)
all:
@echo "当前日期是: $(date)"
运行make命令后,输出结果如下:
当前日期是: Sat Jun 18 15:14:28 CST 2023