Makefile 常用函数

本文详细介绍了Makefile中几个重要的函数,包括$(join)用于合并列表,$(wildcard)用于匹配文件,$(notdir)用于提取文件名。这些函数在构建自动化任务时非常有用,例如文件操作和路径处理。
摘要由CSDN通过智能技术生成

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,并执行指定的文本内容。前两个参数,varlist将首先扩展,注意最后一个参数‘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
  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值