Makefile
Makefile
Kayer什么是Makefile
Makefile 是一个特殊的文件,通常用于管理和自动化软件的构建过程。它包含了一系列的指令,这些指令定义了如何编译和链接程序。Makefile 与 make 工具一起使用,make 是一个构建自动化工具,它会查找 Makefile 文件,并根据其中的指令来构建程序。
Makefile 的基本结构通常包括以下几个部分:
- 目标(Targets):这是构建过程中的一个步骤,比如编译一个源文件或安装程序,即最终要生成的目标文件
- 依赖(Dependencies):目标需要的文件,如果这些文件发生变化,目标将被重新构建,即目标文件由哪些文件生成
- 命令(Commands):生成目标的命令序列,即通过执行该命令,使依赖文件生成目标文件
基本规则
1 | Targets:Dependencies |
Makefile文件的命名:makefile或者Makefile
下面是一个简单的makefile文件
1 | main: main.c func1.c func2.c |
然后执行make
命令,即可生成目标文件
Makefile工作原理
若想生成目标,检查规则中的所有的依赖文件是否都存在
如果有的依赖文件不存在,则向下搜索规则,看是否有生成该依赖文件的规则
如果有规则用来生成该依赖文件,则执行规则中的命令生成依赖文件
如果没有规则用来生成该依赖文件,则报错。
如果所有依赖都存在,检查规则中的目标是否需要更新,必须先检查它的所有依赖,依赖中有任何一个被更新,则目标必须更新(检查的规则是哪个时间大哪个最新)
若目标的时间>依赖的时间,不更新
若目标的时间<依赖的时间,则更新
总结
- 分析各个目标和依赖之间的关系
- 根据依赖关系自底向上执行命令
- 根据依赖文件的时间和目标文件的时间确定是否需要更新
- 如果目标不依赖任何条件,则执行对应命令,以示更新(如:伪目标)
刚刚的例子中,我们不难发现,只要修改了其中一个文件,那么所有的文件都要重新编译,非常浪费资源,因此我们可以通过Makefile的工作原理修改一下刚刚的简单案例
1 | main: main.o func1.o func2.o |
这时候,执行make
命令,会先检查依赖条件是否都存在
- 如果不存在,会向下寻找生成依赖文件的规则。
- 如果存在,就会比较目标时间和依赖的生成时间,来决定是否更新目标。
Makefile中的变量
但是,如果一个项目有多个文件呢?难道我们要一个一个的添加对应的规则吗?那如果是这样编写makefile文件就太麻烦了,因此,在makefile中提供了变量,来使我们简化这些操作。
在 makefile 中使用变量有点类似于C语言中的宏定义,使用该变量相当于内容替换,使用变量可以使makefile易于维护,修改起来变得简单。makefile 有三种类型的变量:
- 普通变量
- 自带变量
- 自动变量
普通变量
- 变量定义直接用
=
- 使用变量值用
$(变量名)
例:下面是变量的定义和使用
1 | obj = abc # 定义变量并赋值 |
自动变量
$@
:表示规则中的目标$<
:表示规则中的第一个条件$^
:表示规则中的所有条件,组成一个列表,以空格隔开,如果这个列表中有重复的项则消除重复项。
模式规则
如果有多个重复的规则,可以使用模式规则
在规则的目标定义中要包含%
,它表示一个或多个
在依赖条件中同样可以使用%
,依赖条件中的%
的取值取决于其目标
比如:
1 | #多个重复的规则 |
Makefile函数
makefile中的函数有很多,这里介绍其中最常用的两个:
- wildcard:查找指定目录下的指定类型的文件
src=$(wildcard *.c)
找到当前目录下所有后缀为.c的文件,赋值给 src
- patsubst:匹配替换
obj=$(patsubst %.c,%o,$(src))
把src变量里所有后缀为.c的文件替换成.o
如当前目录下有main.c fun1.c fun2.c
src=$(wildcard*.c)
等价于 src=main.c fun1.c fun2.c
obj=S(patsubst %.c,%o,$(src))
等价于 obj=main.o fun1.o fun2.o
把刚刚的例子修改为
1 | target = main #自定义目标变量 |
Makefile的清理操作
用途:清除编译生成的中间.o文件和最终目标文件
命令 make clean
如果当前目录下有同名 clean 文件,则不执行 clean 对应的命令
解决方案:
- 伪目标声明:.PHONY:clean
- 声明目标为伪目标之后,makefile将不会检查该目标是否存在或者该目标是否需要更新
clean 命令中的特殊符号:
-
此条命令出错,make 也会继续执行后续的命令。如:-rm main.o
rm -f:强制执行,比如若要删除的文件不存在,使用 -f 不会报错
- @不显示命令本身,只显示结果。如:@echo clean done
makefile最终版本
1 | target = main #自定义目标变量 |