一、make/Makefile 是什么?
1、make 是什么?
首先明确,make 是Linux 下的一条非常重要的指令。
Linux环境下,在对一些大型项目进行编译的时候,会存在上千甚至上万份的文件,这时候就不能一个一个去用 gcc/g++ 编译了,这样不仅浪费时间,而且浪费了大量的人力资源。而且如果对代码进行了修改,那么就又要这样繁琐的工作又要再来一次,这恐怕对于很多需要不断维护的大项目来说,简直就是噩梦。
所以引入了 make 指令来间接调用 gcc/g++ 编译,如果我们更动过某些原始码档案,则 make 也可以主动的判断哪一个原始码与相关的目标文件档案有更新过, 并仅更新该档案。这样可以减少重新编译所需要的时间,也会更加方便。
2、Makefile 文件是干什么的?
首先明确,Makefile 是 Linux 下的需要通过人为编写的文件。
上面所提到的 make 指令,之所以能够帮助码农们快速的编译、维护代码,最主要的功劳还是 make 指令调用读入了 Makefile 文件,所以如果没有 makefile 文件,那么 make 指令也是无法达到它对完美的追求的。
二、如何使用make/makefile?
正如刚才所提到的,想要使用 make 指令的前提是必须人为编写好 Makefile 文件。
1、程序编译的过程理解
首先,我们要理解 make 指令和 Makefile 文件都是用来简化编译过程的。所以想要更好的理解它们的用法,我们首先就需要理解代码编译的过程。
编译的过程,大致可以分为 4 个部分来理解:(以 F.h、F.c、Main.c为例)
1、预处理(-E):
对代码进行头文件的展开、宏替换、条件编译、去掉注释
生成:F.i Main.i
2、编译(-S):
语法检查、生成汇编代码
生成:F.s Main.s
3、汇编(-c)
转换成机器码
生成:F.o Main.o
4、链接
链接成可执行文件(链接分为:动态链接(gcc默认)、静态链接)
生成:a.out
2、Makefile 文件的基础编写语法规则
理解了程序的编译过程之后,首先了解以下 Makefile 文件的基础语法规则:
#目标对象:依赖对象
#[Tab]命令操作
main:main.c child.c
gcc main.c child.c -o main
- 在 makefile 文中 # 表示批注;
- [Tab] 表示在命令行的(制表)字符;
- 目标对象 和 依赖对象 需要用 : 来分隔;
以Main.c 为例 编写 Makefile 文件:
make 执行后:
执行完毕之后,我们再查看当前目录(会发现,它将我们编译过程所要用到的文件都生成了出来):
总结以下,会发现我们刚才所编写的 Makefile 文件执行了以下的步骤:
1、首先明确,我们最终的目标是生成 Main 可执行程序,但是想要生成 Main 需要通 gcc Main.o -o Main,但是我们当前的目录下没有 Main.o 文件,所以我们需要生成 Main.o 文件,然而 Main.o 文件又需要 Main.s 文件来支持,所以又需要生成 Main.s 文件……
2、一共执行了 4 条指令
gcc -E Main.c -o Main.i
gcc -S Main.i -o Main.s
gcc -c Main.i -o Main.o
gcc Main.o -o Main
其次,再编译完成之后,我们需要清理工程文件,所以我们对 Makefile 文件,进行了修改:
其中 .PHONY 是将 clean 对象声明为伪对象,make在执行规则时不会去试图去查找隐含规则来创建它。这样就提高了make的执行效率,也解决了文件目录中如果出现名为clean文件,clean操作不被执行的问题。
执行 make clean 指令:
查看当前目录:
3、Makefile 文件的 预定义变量 写法
预定义变量:
$@: 目标对象
$^: 所有的依赖对象
$<: 依赖对象中的第一个
.PHONY 用于声明伪对象:不管目标对象是否存在,是否最新,每次都重新生成。
执行 make 后: