一. 为什么需要 Makefile
我们都知道在 Linux 下可以使用 gcc
来编译源程序, 当源文件不多的时候, gcc
足以承担编译的工作. 但是一个工程的源文件不计其数, 按照其类型, 功能, 模块分别放在若干个目录当中, 每次使用 gcc 进行编译无疑会使得编译效率低下, 于是项目自动化构建工具 Makefile 就应运而生了.
自动化编译
Makefile 定义了一系列的规则来指定: 哪些文件需要先编译, 哪些文件需要后编译, 甚至于进行更复杂的功能操作. Makefile 带来的好处就是"自动化编译", 一旦写好, 只需一个 make
命令, 整个工程完全自动编译, 极大地提高了软件开发的效率. make是一条命令, Makefile是一个文件,两个工具搭配使用, 完成项目自动化构建.
二. 如何使用 make/Makefile
创建 makefile / Makefile 文件
touch Makefile
创建 Makefile 文件.
接下来, 我们需要在 Makefile 文件中阐明多个文件之间的依赖关系 & 依赖方法.
依赖关系 & 依赖方法
在使用 make/Makefile 前我们首先应该理解各个文件之间的依赖关系 以及它们之间的依赖方法.
- 依赖关系: 文件 A 的变更会影响到文件 B, 那么就称文件 B 依赖于文件 A.
例如: hello
文件是由 hello.c
文件通过预处理, 编译, 汇编, 链接之后生成的文件, 所以hello.c
文件的变更会影响 hello
文件, 所以说 hello
文件依赖于 hello.c
文件.
- 依赖方法: 如果文件 B 依赖于文件 A, 那么通过文件 A 得到文件 B 的方法, 就是文件 B 依赖于文件A 的依赖方法.
例如: hello
文件依赖于 hello.c
文件, 而 hello.c
通过 gcc hello.c -o hello
指令就可以得到 hello
, 那么 hello
依赖于 hello.c
的依赖方法就是 gcc hello.c -o hello
.
vim Makefile
打开 Makefile 文件, 并在其中编辑好 hello
和 hello.c
的依赖关系和依赖方法.
创建出 hello.c
文件并在其中编辑文本.
执行 make
指令, 并运行可执行文件 hello
.
项目清理
在我们每次重新生成可执行程序前,都应该将上一次生成可执行程序时生成的一系列文件进行清理,但是如果我们每次都手动执行一系列指令进行清理工作的话,未免有些麻烦,因为每次清理时执行的都是相同的清理指令,这时我们可以将项目清理的指令也加入到 Makefile 文件当中.
显示执行 make clean
指令.
像 clean 这种没有被第一个目标文件直接或间接关联的文件, 那么它后面所定义的命令将不会被自动执行.
提示: 一般将这种 clean 的目标文件设置为伪目标, 用.PHONY修饰. 伪目标的特性是: 总是被执行.
Makefile 文件中依赖关系的简写方式
- $@: 表示依赖关系中的目标文件 (冒号左侧)
- $^: 表示依赖关系中的依赖文件 (冒号右侧)
上图中的依赖关系可以改写为:
三. make/Makefile 的一些问题
stat 指令
我们可以通过 stat
指令来查看源文件和可执行文件的所有属性, 重点需要关注如下属性.
- Access: 最后一次访问该文件的时间.
- Change:最后一次改变该文件属性的时间.
- Modify:最近一次修改文件内容的时间.
make 命令的执行机制
当我们使用 make
命令生成目标文件后, 再次 make 就会得到 'hello' is up to date (hello 文件已经是最新的) 的信息.
那么 make
指令是否执行, 究竟取决于什么呢?
取决于目标文件与其所依赖的文件的 Modify 时间谁更新.
可以看到目标文件 hello
的 Modify 时间在 hello .c
文件的 Modify 时间之后, 所以 make
指令不执行.
当目标文件 hello
的 Modify 时间在 hello .c
文件的 Modify 时间之前, make
指令执行, 无论目标文件是否存在.