1. makefile中的几个重要函数
1.1 Wildcard 和patsubst
$(patsubst pattern,replacement,text),用于替换,函数参数有三个,
$(wildcard pattern) 返回已经存在的、使用空格分开的、匹配此模式的所有文件列表
一般使用patsubst 和wildcard 函数配合, 得到 .o 文件的文件名。
参考https://www.jianshu.com/p/523726ef5c3b,假设当前路径下有三个cpp文件:circle.cpp square.cpp test.cpp
SRCS = $(wildcard *.cpp) OBJS = $(patsubst %.cpp, %.o, $(SRCS)) |
其中,%可以认为是匹配任意字符,%.cpp 可以用vpath 来指定匹配模式
则SRCS的值就是“circle.cpp square.cpp test.cpp"。
则OBJS的值就是“circle.o square.o test.o”。
1.2. dir 和notdir
$(dir names...) 函数的参数 为names,比如是一个*.cpp的文件名,如果有多个参数,参数间用空格隔开,返回值为所有参数文件所在的所有 路径信息。官方说明如下:
Extracts the directory-part of each file name in names. The directory-part of the file name is everything up through (and including) the last slash in it. If the file name contains no slash, the directory part is the string ‘./’. For example,
$(dir src/foo.c hacks) produces the result ‘src/ ./’.
$(notdir names...) notdir的作用就是去掉目录信息,使得文件列表里只有文件名。
1.3 addprefix
$(addprefix prefix,names...) 函数,用于对names增加前缀,前缀是固定的,names可以有多个。官方说明如下:
The argument names is regarded as a series of names, separated by whitespace; prefix is used as a unit. The value of prefix is prepended to the front of each individual name and the resulting larger names are concatenated with single spaces between them. For example,
$(addprefix src/,foo bar) produces the result ‘src/foo src/bar’.
SRCS = $(wildcard *.cpp) OBJS = $(patsubst %.cpp, %.o, $(SRCS)) OBJECT := $(addprefix obj/, $(notdir $(OBJS))) |
则OBJECT的值就是“obj/circle.o obj/square.o obj/test.o”。
2. Makefile中的变量
Makefile里可以用= := += 来定义变量,使用时用$(变量)获得变量的值。
如果直接用 = ,则make 会将整个makefile展开后,再决定变量的值。也就是说,变量的值将会是整个makefile中最后被指定的值。
“:=”表示变量的值决定于它在makefile中的位置,而不是整个makefile展开后的最终值。
+= 是添加
x = foo y = $(x) bar x = xyz |
在上例中,y的值将会是 xyz bar ,而不是 foo bar 。
如果上述都是:= , 则 y的值将会是 foo bar
参考:https://zhidao.baidu.com/question/450144061.html
3. Makefile中常用的shell命令
Shell 命令 [ ! -e $(dir $@) ] 是一个条件表达式 -e 是文件测试运算符,类似与 test命令 的功能
条件表达式要放在方括号之间,并且要有空格,例如:[$a==$b]是错误的,必须写成[ $a == $b ]。
来自 <https://www.runoob.com/linux/linux-shell-basic-operators.html>
4. Makefile规则
target... : prerequisites ... command |
target也就是一个目标文件,可以是Object File,也可以是执行文件。还可以是一个标签(Label),对于标签这种特性,在后续的“伪目标”章节中会有叙述。
Prerequisites, 依赖文件,就是要生成那个target所需要的文件或是目标。
command也就是make需要执行的命令。(任意的Shell命令)
这是一个文件的依赖关系,也就是说,target这一个或多个的目标文件依赖于prerequisites中的文件,其生成规则定义在command中。说白一点就是说,prerequisites中如果有一个以上的文件比target文件要新的话,command所定义的命令就会被执行。这就是Makefile的规则。也就是Makefile中最核心的内容。
在command中,经常会用到三个重要的变量:
$@--表示规则中的目标文件,target
$^--表示规则中的所有的依赖文件,prerequisites
$<--表示规则中的第一个依赖文件。
参考 https://blog.csdn.net/weixin_38391755/article/details/80380786
https://blog.csdn.net/haoel/article/details/2886
5. make 的工作流程
edit : main.o kbd.o command.o display.o gcc -o edit main.o kbd.o command.o display.o |
在默认的方式下,也就是我们只输入make命令。那么,
1、make会在当前目录下找名字叫“Makefile”或“makefile”的文件。
2、如果找到,它会找文件中的第一个目标文件(target),在上面的例子中,他会找到“edit”这个文件,并把这个文件作为最终的目标文件。(所以,我们的makefile中,必须要把生成最终的simulation这个命令放在前面)
3、如果edit文件不存在,或是edit所依赖的后面的 .o 文件的文件修改时间要比edit这个文件新,那么,他就会执行后面所定义的命令来生成edit这个文件。
4、如果edit所依赖的.o文件也存在,那么make会在当前文件中找目标为.o文件的依赖性,如果找到则再根据那一个规则生成.o文件。(这有点像一个堆栈的过程)
5、当然,你的C文件和H文件是存在的啦,于是make会生成 .o 文件,然后再用 .o 文件生命make的终极任务,也就是执行文件edit了。
参考 https://blog.csdn.net/haoel/article/details/2886
6. vpath
如在某个目录中,除了源代码文件之外,还有不少的说明文档。如果在查找的时候,将所有的文件都判断一遍,那无疑会增加系统编译的时间。为此有时候,系统管理员不仅需要指定make命令查找的路径,而且还需要指定匹配的模式。如现在系统管理员希望make命令查找指定路径下的以.h结尾的文件。要实现这个需求,就需要用到另一个变量vpath。
vpath根据所带参数的不同,这个命令主要用来完成三项工作:
(1) 什么参数都不带的情况下,指清除所有已经设置好了的文件搜索目录。注意其清除vpath命令所设置的搜索路径,而不影响VPATH变量所设置的查找路径。
(2) 带一个参数pattern,如vpath %.h。此时系统会清除符合模式的文件的搜索路径。
(3) 带两个参数,如vpath %.h ..(这个命令表示在上级目录中查找.h文件)。两个参数(匹配模式与文件的搜索路径)都带齐的话,就表示在指定的目录中按规定的模式进行查找。不过需要注意的是,这里一个模式最好对应一条语句。也就是说,在一个vpath语句中定义一个匹配模式。如果要定义多个匹配模式的话,此时最好的办法是连续使用vpath语句来定义,以指定不同的搜索策略。
有的系统中操作系统中,可以相同模式的情况下定义多个路径。如vpath %.h all、vpath %.h bll 、vpath %.h cll等等。此时后面对定义不会覆盖前面的定义。即三个语句是各自独立的,三个语句定义的变量都有效。
举例:vpath %.cpp $(dir ./*.cpp ),则makefile中其他地方使用%.cpp时,就表示只在路径./下的所有.cpp文件。
https://blog.csdn.net/zcf1002797280/article/details/50420772
7. Makefile错误
makefile:2: *** missing separator. Stop.
解决方法 命令前面用TAB键,而不能用4个空格