Makefile常用函数
前言
学习杜老师推荐的Makefile教程视频,链接。记录下个人学习笔记,仅供自己参考。
之前有转载过杜老师的从零Makefile落地算法大项目文章,感兴趣的可以看看。
本课程主要讲解Makefile中的常见函数。
0.导言
Makefile函数调用,很像变量的调用,也是以 $
来标识的,其语法如下:
$(fn, arguments) or ${fn, arguments}
- fn:函数名
- arguments:函数参数,参数间以逗号
,
分隔,而函数名和参数之间以空格
分隔
1.shell
$(shell <command> <arguments>)
- 名称:shell命令函数 —— shell
- 功能:调用 shell 命令 command
- 返回:函数返回 shell 命令 command 的执行结果
示例如下:
# shell 指令,src 文件夹下找到 .cpp 文件
cpp_srcs := $(shell find src -name "*.cpp")
# shell 指令, 获取计算机架构
HOST_ARCH := $(shell uname -m)
debug :
@echo $(cpp_srcs)
@echo $(HOST_ARCH)
.PHONY : debug
输出如下:
src/main.cpp
aarch64
2.subset
$(subst <from>,<to>,<text>)
- 名称:字符串替换函数 —— subst
- 功能:把字串 <text> 中的 <form> 字符串替换成 <to>
- 返回:函数返回被替换过后的字符串
示例如下:
# shell 指令,src 文件夹下找到 .cpp 文件
cpp_srcs := $(shell find src -name "*.cpp")
# subst 将src/替换为objs/
cpp_objs := $(subst src/,objs/,$(cpp_srcs))
# subst 将.cpp替换为.o
cpp_objs := $(subst .cpp,.o,$(cpp_objs))
debug :
@echo $(cpp_srcs)
@echo $(cpp_objs)
.PHONY : debug
输出如下:
src/main.cpp
objs/main.o
3.patsubst
$(patsubst <pattern>,<replacement>,<text>)
- 名称:模式字符串替换函数 —— patsubst
- 功能:通配符
%
,表示任意长度的字符,从 text 中取出 pattern, 替换成 replacement - 返回:函数返回被替换过后的字符串
- 区别:
subst
函数只能进行简单的字符串替换,而patsubst
函数则可以根据通配符进行更加灵活的字符串替换
示例如下:
# shell 指令,src 文件夹下找到 .cpp 文件
cpp_srcs := $(shell find src -name "*.cpp")
# patsubst 将src/*.cpp替换为objs/*.o
cpp_objs := $(patsubst src/%.cpp,objs/%.o,$(cpp_srcs))
debug :
@echo $(cpp_srcs)
@echo $(cpp_objs)
.PHONY : debug
输出如下:
src/main.cpp
objs/main.o
4.foreach
$(foreach <var>,<list>,<text>)
- 名称:循环函数 —— foreach
- 功能:把字符串<list>中的元素逐一取出来,执行<text>包含的表达式
- 返回:<text>所返回的每个字符串所组成的整个字符串 (以空格分隔)
示例如下:
include_paths := src \
/usr/include/opencv4
library_paths := /usr/lib/aarch64-linux-gnu \
/usr/local/cuda-10.2/lib64
include_paths := $(foreach item,$(include_paths),-I$(item))
library_paths := $(library_paths:%=-L%)
debug :
@echo $(include_paths)
@echo $(library_paths)
.PHONY : debug
输出如下:
-Isrc -I/usr/include/opencv4
-L/usr/lib/aarch64-linux-gnu -L/usr/local/cuda-10.2/lib64
foreach
类似于python的for ... in
,伪代码如下:
for item in include_paths:
item = f"-I{item}"
5.dir
$(dir <names...>)
-
名称:取目录函数 —— dir
-
功能:从文件名序列<names>中取出目录部分。目录部分是指最后一个反斜杠(\)之前的部分。如果没有反斜杠,那么返回.\
-
返回:返回文件名序<names>的目录部分
示例如下:
cpp_srcs := $(shell find src -name *.cpp)
cpp_objs := $(patsubst src/%.cpp,objs/%.o,$(cpp_srcs))
objs/%.o : src/%.cpp
@mkdir -p $(dir $@)
@g++ -c $^ -o $@
compile : $(cpp_objs)
debug :
@echo $(cpp_srcs)
@echo $(cpp_objs)
.PHONY : debug compile
6.notdir
$(notdir <names...>)
- 名称:去目录函数 —— notdir
- 功能:从文件名序列<name>取出非目录部分。非目录部分是指最后一个反斜杠(\)之后
- 返回:返回文件名序列<name>的非目录部分。
示例如下:
libs := $(notdir $(shell find /usr/lib -name lib*))
debug :
@echo $(libs)
.PHONY : debug
Tips:链接静态库只需要使用-l
和-L
参数即可(-l
参数可具体指定需要链接的库,-L
参数可以指定需要链接的库文件路径),而动态库除了使用-l
和-L
参数外,还需要使用-rpath
和-Wl
参数,其中,-rpath
参数指定了运行时搜索动态库的路径,-Wl
参数则将后续的选项传递给链接器ld。具体来说,-Wl,-rpath
参数可以设置动态库搜索路径。(from ChatGPT)
7.filter
$(filter <names...>)
- 名称:过滤函数 —— filter
- 功能:过滤出符合条件的字符串
- 返回:返回符合条件的字符串列表
示例如下:
libs := $(notdir $(shell find /usr/lib -name lib*))
a_libs := $(filter %.a,$(libs))
so_libs := $(filter %.so,$(libs))
debug :
@echo $(a_libs)
.PHONY : debug
8.basename
$(basename <names...>)
- 名称:去目录和后缀函数 —— basename
- 功能:从文件名序列<names>中取出非目录部分和后缀部分。非目录部分是指最后一个反斜杠(\)之后的部分,后缀部分是指最后一个点(.)之后的部分
- 返回:返回文件名序列<name>的非目录部分和后缀部分
libs := $(notdir $(shell find /usr/lib -name lib*))
a_libs := $(subst lib,,$(basename $(filter %.a,$(libs))))
so_libs := $(subst lib,,$(basename $(filter %.so,$(libs))))
debug :
@echo $(so_libs)
.PHONY : debug
总结
本次课程主要学习了Makefile中的常见函数以及它们对应的用法。