# Makefile的写法
# 目录
[toc]
# 1.介绍Makefile
一般指的是GNU make, 目前虽有众多依赖关系检查工具,但是make是应用最广泛的一个。这要归功于它被包含在Unix系统中。斯图亚特·费尔德曼(Stuart Feldman)在1977年在贝尔实验室(Bell Labs)里制作了这个软件,GNU make仿照make的标准功能(透过clean-room工程)重新改写,并加入作者觉得值得加入的新功能,常和GNU编译系统一起被使用,是大多数GNU Linux安装的一部分。
什么是 Makefile, 一个工程中的源文件不计其数,其按类型、功能、模块分别放在若干个目录中, Makefile 文件定义了一系列的规则来指定哪些文件需要先编译,哪些文件需要后编译,哪些文件需要重新编译,甚至于进行更复杂的功能操作,因为 Makefile 文件就像一个 Shell 脚本一样,也可以执行操作系统的命令。
Makefile 带来的好处就是“自动化编译” ,一旦写好,只需要一个 make 命令,整 个工程完全自动编译,极大的提高了软件开发的效率。make 是一个命令工具,是一个 解释Makefile 文件中指令的命令工具,一般来说,大多数的 IDE 都有这个命令, 比如
- Delphi 的 make
- Visual C++ 的 nmake
- Linux 下 GNU 的 make
1.1.工程场景
- 工程场景:当你调试代码的时候,遇到这样的场景,到各种路径,添加环境变量
- 然后编译的时候一堆的选项,并且生成一堆文件,如何解决麻烦?makefile✔
$gcc -g -gdwarf-2 -Os -fno-pic -fno-builtin -Wall -nostdlib -std=c99 -fno-exceptions -pipe -fno-aggressive-loop-optimizations -Winvalid-pch -fno-short-enums -S test.c
1
# 2.Makefile 文件命名和规则
文件命名
- makefile 或者 Makefile
Makefile 规则
- 一个 Makefile 文件中可以有一个或者多个规则
目标 ...: 依赖 ...
命令(Shell 命令)
...
1
2
3
2
3
语法易错点:
command是命令行,如果其不与“目标:依赖”在1行,*必须以 Tab
键开头,如果和prerequisites在一行,那么可以用分号做为分隔。比如下面
targets : prerequisites ; command
command
...
1
2
3
2
3
- ⚫ 目标:==最终要生成的文件==(伪目标除外)
- ⚫ 依赖:生成目标==所需要==的文件或是目标
- ⚫ 命令:通过执行命令对依赖操作生成目标(命令前必须 Tab 缩进)
- Makefile 中的其它规则一般都是为第一条规则服务的。
# 3.工作原理
命令在执行之前,需要先检查规则中的依赖是否存在
- 如果存在,执行命令
- 如果不存在,向下检查其它的规则,检查有没有一个规则是用来生成这个依赖的, 如果找到了,则执行该规则中的命令
# (增量编译)✔
检测更新,在执行规则中的命令时,会比较目标和依赖文件的时间
- 如果依赖的时间比目标的时间晚,需要重新生成目标
- 如果依赖的时间比目标的时间早,目标不需要更新,对应规则中的命令不需要被执行
# 4.变量
◼自定义变量 变量名=变量值 var=hello $(var)
◼定义变量
AR : 归档维护程序的名称,默认值为 ar app:main.c a.c b.c
CC : C 编译器的名称,默认值为 cc gcc -c main.c a.c b.c
CXX : C++ 编译器的名称,默认值为 g++
$@ : 目标的完整名称 #自动变量只能在规则的命令中使用
$< : 第一个依赖文件的名称 app:main.c a.c b.c
$^ : 所有的依赖文件 $(CC) -c $^ -o $@
1
2
3
4
5
6
2
3
4
5
6
◼ 获取变量的值
$(变量名)
1
# 5.模式匹配
add.o:add.c
gcc -c add.c
div.o:div.c %.o:%.c
gcc -c div.c
sub.o:sub.c
gcc -c sub.c
mult.o:mult.c
gcc -c mult.c
main.o:main.c
gcc -c main.c
- %: 通配符,匹配一个字符串
- 两个%匹配的是同一个字符串
%.o:%.c
gcc -c $< -o $@
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
# 6.函数
$(wildcard PATTERN...)
功能:获取指定目录下指定类型的文件列表
参数:PATTERN 指的是某个或多个目录下的对应的某种类型的文件,如果有多个目录,一般使用空格间隔
返回:得到的若干个文件的文件列表,文件名之间使用空格间隔
示例:
$(wildcard *.c ./sub/*.c)
返回值格式: a.c b.c c.c d.c e.c f.c
$(patsubst <pattern>,<replacement>,<text>)
功能:查找<text>中的单词(单词以“空格”、“Tab”或“回车”“换行”分隔)是否符合模式<pattern>,如果匹配的话,则以<replacement>替换。
<pattern>可以包括通配符`%`,表示任意长度的字串。如果<replacement>中也包含`%`,那么,<replacement>中的这个`%`将是<pattern>中的那个%所代表的字串。(可以用`\`来转义,以`\%`来表示真实含义的`%`字符)
返回:函数返回被替换过后的字符串
示例:
$(patsubst %.c, %.o, x.c bar.c)
返回值格式: x.o bar.o
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
# 参考资料
- 陈皓,跟我一起写Makefile
- nowcoder上『高性能服务器开发』笔记
- GNU/make的官网:https://www.gnu.org/software/make/ (opens new window)