文章目录
- 一.前言
- 二.Makefile如何写入/make命令使用
- 2.1清楚依赖关系和依赖方法
- 2.2删除文件
- 2.3Makefile中的关键字.PHONY
- 2.4一个小补充
一.前言
在此之前我们已经可以用vim编写代码和用gcc编译代码。但是如果现在要写一个大型项目,一下子写了很多源文件,在编译它时岂不是要重复使用很多次gcc命令,这样会不会太麻烦了,或者如果不小心写错命令了岂不是更要命。所以在这里我们又要接触两样新事物:make/Makefile.
make:是一个命令
Makefile/makefile:是一个文件(一般在当前源代码路径下),这里M大小写都可以
二.Makefile如何写入/make命令使用
如果要做一件事请,我们首先要清楚两样事情:依赖关系和依赖方法。比如你月底没钱花了要找妈妈要生活费,打电话过去之后,首先得喊一声妈吧,这样才能让你妈知道,电话那头是自己的孩子,这就搞清楚了依赖关系。喊完妈之后再给自己母亲说明打电话的原因,然后你妈打钱给你,这个流程就是依赖方法。这两样事情都做正确了,你才能从你妈那里要到生活费。
同样你如果需要Makefile文件和make指令帮你完成一项任务,你首先要让它知道这个任务所需要的依赖关系和依赖方法。
知道这些东西后,我们就开始用make命令来帮我们执行一次简单的任务–编译我们的.c源文件。
-
首先我们需要在Makefile内写一些指令:
-
接下来退出之后用make命令
直接make一下,就自动去寻找Makefile文件,然后就生成了myfile的可执行文件。方法很简单,但是Makefile里面写的是啥还不清楚。接下来主要讲讲如何编写Makefile里面的内容。
2.1清楚依赖关系和依赖方法
编写Makefile的过程就是编写依赖关系和依赖方法的过程。我们最终要依靠myfile.c这个文件得到可执行文件myfile。所以这里的依赖关系就是:myfile这个可执行文件要依赖myfile.c形成。
所以Makefile第一行就写:
//中间用:隔开
myfile:myfile.c
这行代码冒号左边的,我们称为目标文件,右边的称为依赖文件列表(右边可以有很多文件,中间用空格隔开)
随后我们要清楚依赖方法,就是如何用myfile.c文件生成myfile这个程序,所以第二行要这样写:
gcc -o myfile myfile.c
注意第二行一定要用两个空格隔开。不要问为啥,语法规定就是要这样写。
写完之后保存退出,在用make指令执行就可以了。为了让大家更好的理解依赖关系和依赖方法这两个概念,我将代码写的更细一点
myfile:myfile.o
gcc -o myfile myfile.o
myfile.o:myfile.s
gcc -c -o myfile.o myfile.s
myfile.s:myfile.i
gcc -S -o myfile.s myfile.i
myfile.i:myfile.c
gcc -E -o myfile.i myfile.c
make指令在执行这个文件时会先看第一行,可执行文件要依赖.o的汇编文件生成,但是此时还没有这个.o文件,所以程序会继续向下寻找,.o文件要依靠.s文件来生成,但是.s文件也同样没有,所以继续向下寻找…最后.i文件要依靠.c文件来生成。现在我们刚好有一个.c文件,所以会开始执行下面的gcc指令,从而生成了.i文件。有了.i文件,程序会一步一步回去,逐步生成.s,.o,可执行文件。这很像函数递归的样子。你也可以理解为这是数据结构里的栈:上面的依赖关系是入栈,下面的依赖方法是出栈。
直接make命令执行,就可以得到四个文件。
2.2删除文件
依赖关系中,依赖文件列表可以没有,没有的话也同样会执行下面的依赖方法。
所以如果要写一个删除文件的代码,可以这样写:
clean:
rm -f myfile.i myfile.s myfile.o myfile
既然能学到这里,我相信一个简单的删除指令就不用我多说了吧~。下面的这个rm指令就相当于依赖方法。
接下来我们就可以用make指令来执行这个程序了:
因为make默认会执行第一组依赖方法和依赖关系,所以这里在make后面加上需要的目标文件,也就是clean,目的就是让执行clean这一组依赖关系和依赖方法。
然后就可以发现我们这个目录下的四个文件的确被删除掉了。
2.3Makefile中的关键字.PHONY
我们刚刚已经可以用Makefile来帮助我们编译自己的程序或者删除文件。但是现在还有些缺陷,就是你用make命令只能执行一次,像这样:
第一次时可以正常运行,但是第二次的时候会说myfile这个文件已经是最新的了,不让你在执行命令了。我们将这种现象称为:不是总是被执行的。俗一点的说这个目标文件只能执行一次,不让你一直执行。
如果现在希望让他每次make都能运行成功的话,就再加一条命令:
.PHONY:myfile
myfile:myfile.c
gcc -o myfile myfile.c
在这里我们如果希望myfile这个目标文件总是被执行,所以前面添加上这样一个关键字。
我们将.PHONY后面跟的文件叫做伪文件
现在发现一直重复执行make,也能成功了:
但是一般在编译的时候不建议这样写,一般把这个编译器放在删除命令那边,向下面这样写:
myfile:myfile.c
gcc -o myfile myfile.c
.PHONY:clean
clean:
rm -f myfile
在平时可能看不出来,在一些大型项目编译的时候是很花时间的,所以不推荐将编译生成可执行程序这一块加上,PHONY这个关键字。但是删除就不一样了,你想删一次或多次都没啥影响的。(其实不加这个关键字,你一直删也没啥问题)
2.4一个小补充
刚在我们看到如果没有.PHONY这个关键词修饰的话,可执行程序只能被make命令执行一次,但是make命令是怎么知道我们这个可执行程序是最新的呢?
因为在系统中我们可以想象出有两条时间线(源代码和可执行程序):
首先源文件写完后的时间肯定要早于可执行程序运行的时间:
make指令就会判断可执行程序运行后的程序是否晚于源文件运行的时间,如果是就说明这个可执行程序是最新的。如果你修改过了这个源文件,那可执行程序的时间就要晚于源文件的时间,此时你在编译源文件,make就会帮你去完成了。
make指令,我们可以稍微“欺骗”一下。可以用touch这个指令。touch指令是:如果后面跟的那个文件不存在,就会帮你生成一个新的文件,如果后面这个文件存在,就会帮你更新这个文件的时间为最新时间。