什么是Makefile?
看一看它的官方解释:
一个工程中的源文件不计其数,其按类型、功能、模块分别放在若干个目录中,makefile定义了一系列的规则来指定,哪些文件需要先编译,哪些文件需要后编译,哪些文件需要重新编译,甚至于进行更复杂的功能操作,因为 makefile就像一个Shell脚本一样,其中也可以执行操作系统的命令。
简单的理解就是,Makefile就是一个比较特别的文件,在这个文件里边定义了一些规则,来帮助我们同时编译多个源文件。
make又是什么?为什么要使用make?
make是一个命令工具,是一个解释Makefile文件中指令的命令工具。Make工具最主要也是最基本的功能就是通过makefile文件来描述源程序之间的相互关系并自动维护编译工作
总结:make是一条命令,Makefile是一个文件,两者搭配使用,可完成项目自动化构建
接下来就来仔细讲讲它们是怎么搭配使用的。
Makefile文件的编写
Makefile文件里边内容的定义格式为:
![](https://i-blog.csdnimg.cn/blog_migrate/ad4be42f33a451b0966b32d7f93ac6fe.png)
要使用Makefile文件来编译多个源文件,首先得有多个文件吧,本篇博客就以写一个加 减 乘 除为例
使用touch命令创建多个文件,将其放到一个math目录里边管理起来(养成将一个工程用一个目录管理起来的好习惯)
![](https://i-blog.csdnimg.cn/blog_migrate/361c79e7805cb9dc13c0ff6437131349.png)
然后使用vim命令将文件逐个打开,写入程序
![](https://i-blog.csdnimg.cn/blog_migrate/d87e4f3755418431e159c6feed43b5b6.png)
接下来就是编辑Makefile文件里边的内容了
方式一:
按 i 进入编辑模式,然后输入
main:main.o add.o sub.o mul.o div.o (
在这里把目标文件命名为main
)
这行的意思其实就是目标文件 main 的生成依赖于
main.o add.o sub.o mul.o div.o 这五个文件
gcc main.o add.o sub.o mul.o div.o -o main 注意:在这一行一定要是先按一个Tab键后再输入命令
这行命令的意思就是通过所有的 .o 文件生成一个main。但是现在我们只有几个 .c 文件,
这里的一系列 .o 文件并不存在。其实这些.o文件都是依赖于.c文件产生的,所以,接下来还需要利用 已经存在的 .c文件将这些.o文件生成,也就是通过如下内容
add.o : add.c
gcc -c add.c -o add.o
这两句的理解跟上边两句的理解都一样,在此就不多说了
这样就可以得到add.o文件了,其他的几个.o文件也是以同样的方式得到的。
具体内容如下:
![](https://i-blog.csdnimg.cn/blog_migrate/ba124edb59cc88c1ef900616f95e6caf.png)
make的使用
Makefile文件里边的内容编辑完了之后,保存退出
然后使用命令 make, 所有的文件就已经替我们编译好了
注意:make命令后边什么都没有跟的话它会自动执行第一个目标后边的命令,如果在后边加了一个目标文件,那么,它会执行该目标文件后边的命令。
比如说我就输入一个make,然后回车,那么它会执行第一个目标文件main后边的命令,也就是gcc main.o add.o sub.o mul.o -o div.o main 这句命令。但是在执行命令之前他是会检查依赖文件是否存在的,如果存在,就执行命令,如果不存在,就会很智能的寻找新的规则用来生成依赖文件。此时的依赖文件就变成一个子目标,向下寻找。这么说,可能会有点抽象。画个图可能会好理解一点。
![](https://i-blog.csdnimg.cn/blog_migrate/000f7b6b7eb0ab10a9a2ab54e541e007.png)
从图中可以看出,虽然使用make它是自动执行第一个目标后边的内容,但是由于它会智能地去寻找生成依赖文件,所以它将我们整个Makefile文件除了clean及其后边的命令外都执行了。来看一看事实上是不是这样呢?
![](https://i-blog.csdnimg.cn/blog_migrate/489df4eeb24bbcfbfebf4b1199755178.png)
使用make指令,将我们需要的 .o 文件根据我们在Makefile文件里边的顺序编译得到,然后利用这些.o文件生成我们的最终目标。(其实这个main就相当于当个源文件编译成功后的 a.out)
然后执行一下目标文件,使用命令 ./main
![](https://i-blog.csdnimg.cn/blog_migrate/c3b2e687f2646b4ce55f78c42494e6b2.png)
结果就出来了。
如果发现有些文件里的内容运行结果有错,那么,将这些文件修正之后,再次执行make命令,然后就会发现,修改后的文件会进行重新编译,而那些没有修改过的文件就不会再编译了。所以,事实上,这个make在执行的时候是会比较一个时间戳的,意思就是,在如果一个文件比上一次执行make时的时间旧,那么,这一次执行make就不会再对该文件进行编译了。所以,每次使用完make,最好在使用make clean 将所有的 .o 文件删除,这样的话,每次编译就会将所有的文件重新编译。
说明:如果一个目录中已经有了clean 这样一个文件,然后我再使用make clean,因为比较时间戳的原因,就不执行目标文件clean后边的命令了。
为了解决这种情况,可以在Makefile文件的最开始一句 .PHONY clean ---- 意思就是说不管这个clean是不是最新的,它都会执行clean后边的指令。通常也会把main加在后面,以防止这个目录里边已经有一个名为main的文件了而不执行目标文件main。
使用命令 rm -rf *.o 删除所有的.o文件,来剖析一下这条命令 。rm是用于删除文件的,r和f是它的参数,r表示递归删除,f表示强制删除
*.o表示所有的.o文件
看一看执行make clean 的效果
![](https://i-blog.csdnimg.cn/blog_migrate/f5b99e33312f86aaec74534494bd2247.png)
所有的 .o 文件都没有了。
方式二:
其实Makefile文件里边的很多内容都是重复的,如果嫌这样太麻烦了,可以使用一种新的简单一点的方式来实现,那么,我们可以先将之前的Makefile文件备份一份(这个备份是方便自己以后看的,也可以不用备份)
通过命令 cp Makefile Makefile1 实现备份
然后vim Makefile 打开该文件,对里边的内容重新进行编辑,使用 $^ 来表示所有的依赖文件 用$@ 代表目标文件
![](https://i-blog.csdnimg.cn/blog_migrate/0c7717c77a0fea45f4e7750be8a330ae.png)
来看一看结果:
![](https://i-blog.csdnimg.cn/blog_migrate/92c41bf8690cc55fc93d362d2f2664b6.png)
跟第一种方式执行的一模一样。
方式三:
同样的,可以使用 cp Makefile Makefile2 将第二种方式备份一份,然后将其内容修改为新的方式
其实Makefile文件里边就是将所有的.c 文件生成 .o文件,最后再利用所有的.o文件生成一个目标文件main
那么可以将后边的几个.c文件生成.o文件修改为:
%.o : %.c -----表示.o依赖于.c,而%会进行模式匹配,add.o自动依赖于add.c
gcc -c $^ -o $@
![](https://i-blog.csdnimg.cn/blog_migrate/58d2ca3e79caae25a903379f065bcf56.png)
将其保存后看结果
![](https://i-blog.csdnimg.cn/blog_migrate/21fe6f3ee6693a5f47dd60c772a1ce66.png)
跟前两种方式的执行没什么区别。
讲到这里,相信大家对Makefile文件和make指令的理解和他们的搭配使用已经了解的比较清楚了。
PS:如果发现本篇文章有什么不足之处,欢迎各位斧正!