✨个人主页: 熬夜学编程的小林
💗系列专栏: 【C语言详解】 【数据结构详解】【C++详解】【Linux系统编程】
目录
1、背景
2、编写makefile
2、make原理
3、理解makefile
4、优化makefile
总结
1、背景
★ 会不会写makefile,从一个侧面说明了一个人是否具备完成大型工程的能力。
★ 一个工程中的源文件不计数,其按类型、功能、模块分别放在若干个目录中,makefile定义了一系列的规则来指定,哪些文件需要先编译,哪些文件需要后编译,哪些文件需要重新编译,甚至于进行更复杂的功能操作。
★ makefile带来的好处就是——“自动化编译”,一旦写好,只需要一个make命令,整个工程完全自动编译,极大的提高了软件开发的效率。
★ make是一个命令工具,是一个解释makefile中指令的命令工具,一般来说,大多数的IDE都有这个命令,比如:Delphi的make,Visual C++的nmake,Linux下GNU的make。可见,makefile都成为了一种在工程方面的编译方法。
总结:
★ make是一条命令,makefile是一个文件,两个搭配使用,完成项目自动化构建。
2、编写makefile
第一步,先创建两个文件,一个用于编写源代码(test.c),一个用于自动编译源代码(makefile/Makefile)。
[jkl@VMCentos7 lesson4]$ touch test.c makefile # 创建两个文件
[jkl@VMCentos7 lesson4]$ ls
makefile test.c
第二步,编写makefile文件。
test.exe:test.c
gcc test.c -o test.exe
.PHONY:clean
clean:
rm -f test.exe
注意:
- makefile 的文件名必须是 makefile/Makefile,不能是其他名称,否则 make 识别不了。
- 依赖文件可以有多个,也可以没有。
- 依赖方法必须以 [Tab] 键开头,特别注意不能是四个空格。
第三步,编写test.c文件。
#include<stdio.h>
int main()
{
printf("hello linux\n");
return 0;
}
第四步,通过命令看效果。
[jkl@VMCentos7 lesson4]$ make
gcc test.c -o test.exe
[jkl@VMCentos7 lesson4]$ ls
makefile test.c test.exe
[jkl@VMCentos7 lesson4]$ ./test.exe
hello linux
2、make原理
在Linux中,输入make命令后,make会在当前目录下找文件名为 "makefile或者Makefile"的文件,1. 如果找到,则会把文件中的第一个目标文件作为最终的目标文件。
[jkl@VMCentos7 lesson4]$ ls # 查看当前目录的文件,有一个makefile一个Makefile文件
makefile Makefile test.c
[jkl@VMCentos7 lesson4]$ make # 把第一个文件作为目标文件
gcc test.c -o test.exe # 执行makefile
[jkl@VMCentos7 lesson4]$ cat makefile
test.exe:test.c
gcc test.c -o test.exe
.PHONY:clean
clean:
rm -f test.exe
[jkl@VMCentos7 lesson4]$ cat Makefile
mytest:test.c
gcc -o mytest test.c
2. 如果没有找到,则打印提示信息。
[jkl@VMCentos7 ~]$ make
make: *** No targets specified and no makefile found. Stop. # 没有找到目标文件
3、理解makefile
首先我们需要知道makefile文件中代码所代表的意思,通过下图进行一一解释:
注意:上面我们说了输入make指令出现两种可能,此处只讲解找到最终文件的情况。
当我们在命令行中输入make命令,会默认生成第一个目标文件,即执行第一个依赖方法。
[jkl@VMCentos7 lesson4]$ make # 默认执行第一个依赖方法,并打印出来
gcc test.c -o test.exe
[jkl@VMCentos7 lesson4]$ ls # 查看当前目录文件,确实生成了可执行程序(目标文件)test.exe
makefile Makefile test.c test.exe
当我们再次输入make命令,会出现以下提示:
[jkl@VMCentos7 lesson4]$ make
make: 'test.exe' is up to date. # 可执行程序(目标文件)是最新生成的了
1. 为什么再次输入make命令会不让我们继续生成目标文件呢???
因为当有大量的文件的时候,编译执行会消耗大量的时间,为了达到更高的效率,因此源代码没有改变,makefile就会知道只生成一份可执行程序就可以了。
但是此时就有另外的两个问题了,编译器怎么知道哪个文件是没有改变的源代码???如果我们的目的就是想要输入命令则生成目标文件该怎么办???
2. 编译器怎么知道哪个文件是没有改变的源代码???
对比可执行程序最近修改时间与源文件最近修改时间,谁更新?
编写代码和代码生成的可执行程序的修改时间是不一样的,先写的源代码,后才有的代码生成的可执行程序。因此makefile会通过谁的时间更新,来确定到底要不要重新生成可执行程序。通过stat命令可以看到文件的三个时间。
3. 想要输入make命令则生成目标文件该怎么办???
此处可以在每个方法之前输入 .PHONY:xxx,xxx对应的方法总是要执行。xxx可以是目标文件也可以是依赖方法。
举例:想要make总是执行,可以将makefile改成如下内容:
.PHONY:test.exe
test.exe:test.c
gcc test.c -o test.exe
此时输入make则会生成可执行程序。
4. 我们像VS编译一个程序可以生成解决方案,还可以清理解决方案,我们makefile如何清理解决方案呢???
清理解决方案的实质是删除可执行程序,那么我们在makefile中提供一个删除文件的依赖方法即可,而且我们可能总是想要删除可执行程序,因此可以加上.PHONY:xxx。
test.exe:test.c
gcc test.c -o test.exe
.PHONY:clean # 总是执行该依赖关系中的方法
clean: # 删除可执行程序
rm -f test.exe
5. 从上面我们可以看到,删除可执行程序是第二个依赖方法,我们前面知道make默认执行第一个依赖方法,那我们想要执行第二个依赖方法应该怎么办呢??
此处需要使用make命令+目标文件,即make clean。 只要不是第一个依赖方法,都是这样执行依赖方法!!!
[jkl@VMCentos7 lesson4]$ ls
makefile Makefile test.c test.exe
[jkl@VMCentos7 lesson4]$ make clean # 删除可执行程序
rm -f test.exe
[jkl@VMCentos7 lesson4]$ ls # 确实删除了
makefile Makefile test.c
6. 虽然知道了如何执行其他时候的依赖方法,但是此时又有一个问题,如果我执行依赖方法之后不想看到执行的是什么,怎么解决呢???
解决办法是在依赖方法前面加一个@符号,则不会看到执行的内容了。
[jkl@VMCentos7 lesson4]$ cat makefile # 查看文件内容
.PHONY:test.exe
test.exe:test.c
@gcc test.c -o test.exe # 依赖方法中有@
.PHONY:clean
clean:
rm -f test.exe # 依赖方法中没有@
[jkl@VMCentos7 lesson4]$ make # 不显示执行的是什么
[jkl@VMCentos7 lesson4]$ ls
makefile Makefile test.c test.exe # 生成了可执行程序
[jkl@VMCentos7 lesson4]$ make clean # 显示执行的是什么
rm -f test.exe
[jkl@VMCentos7 lesson4]$ ls # 删除了可执行程序
makefile Makefile test.c
4、优化makefile
前面我们理解了makefile中内容的意义,但是在依赖关系和依赖方法之间的文件名基本是重复的,有没有一种方法让它更简便一些呢???
答案是可以的,此处我们需要介绍几个makefile中一些自动化变量。
$@ : 规则的目标 ,即上面的test.exe
$< : 规则的第一个依赖,即test.c
$? : 所有比目标新的依赖的列表
$^ : 所有的依赖的列表,会自动去重 ,即目标后面的多个依赖列表
下面我们则对上面写的makefile文件进行优化:
1.如下为单个依赖关系的举例:
test.exe:test.c
gcc -o $@ $< # 自动化变量需要在最后面 $@代表test.exe $<表示test.c
.PHONY:clean
clean:
rm -f test.exe
2.如下为多个依赖关系的举例:
test.exe:test.c test.h
gcc -o $@ $^ # 自动化变量需要在最后面 $@代表test.exe $^表示test.c 和 test.h
.PHONY:clean
clean:
rm -f test.exe
注意:依赖关系以空格间隔!!!
除了makefile中的自动化变量以外,其实我们还可以自己创建变量。
[jkl@VMCentos7 lesson5]$ cat makefile
bin=test.exe # 创建目标文件变量
src=test.c # 创建被编译文件变量
$(bin):$(src) # 使用需要加$符号
gcc -o $@ $^
.PHONY:clean
clean:
rm -f $(bin)
注意:创建变量跟C语言相似,但是不用加类型。
总结
本篇博客就结束啦,谢谢大家的观看,如果公主少年们有好的建议可以留言喔,谢谢大家啦!