文章目录
- 🌂背景
- 🌂make/Makefile的使用
- 🌂make/Makefile原理
- 🌂项目清理
- 🌂make/Makefile的语法补充
🌂背景
-
会不会写makefile,从一个侧面说明了一个人是否具备完成大型工程的能力一个工程中的源文件不计数,其按类型、功能、模块分别放在若干个目录中,makefile定义了一系列的规则来指定,哪些文件需要先编译,哪些文件需要后编译,哪些文件需要重新编译,甚至于进行更复杂的功能操作。
-
makefile带来的好处就是——“自动化编译”,一旦写好,只需要一个make命令,整个工程完全自动编译,极大的提高了软件开发的效率。
-
make是一个命令工具,是一个解释makefile中指令的命令工具,一般来说,大多数的IDE都有这个命令,比如:Delphi的make,Visual C++的nmake,Linux下GNU的make。可见,makefile都成为了一种在工程方面的编译方法。
-
make是一条命令,makefile是一个文件,两个搭配使用,完成项目自动化构建。
🌂make/Makefile的使用
先看一个简单的使用示例:使用步骤:
- 先创建一个文件,文件名必须是makefile/Makefile,不能是其他名字。
- vim打开该makefile文件,增加第一行:依赖关系 第二行:依赖方法(后面会讲解到)
- 然后退出,输入命令
# make
- 结果,就会生成自己指定的文件
结果:
以上的例子来讲:Makefile文件里面的第一行:
依赖关系:code:test.c意思就是形成code文件,需要依赖test.c
依赖方法:[TAB]gcc -o code test.c 就是应该怎么依赖test.c文件形成code文件,这里就是利用gcc编译test.c文件,形成code文件。
下面通过这样的例子帮助我们更好的理解:(如下图)
🌂解析:
这里是上一章讲的翻译的过程,不知道的可以去看看: link
🌂依赖关系
依赖关系必须用冒号(:)作为分隔符,冒号左边为需要形成的目标文件,右侧是依赖文件列表(可以有多个,空格分开)。
上面的code文件,依赖test.o文件
test.o文件,依赖test.s文件
test.s文件,依赖test.i文件
test.i文件,依赖test.c文件
🌂 依赖方法
拿一行说明:就比如最后一行的依赖关系下面的依赖方法:
# gcc -E -o test.i test.c
就是需要依赖test.c文件,将他预处理后形成test.i文件。
最后指令make后的效果:
我们可以看到,这里执行的顺序和我们写的顺序是相反的,这就要看看make与Makefile的原理了。
🌂make/Makefile原理
make是如何工作的,在默认的方式下,也就是我们只输入make命令。那么,
- make会在当前目录下找名字叫“Makefile”或“makefile”的文件。
- 如果找到,它会找文件中的第一个目标文件(target),在上面的例子中,他会找到“code”这个文件,并把这个文件作为最终的目标文件。
- 如果code文件不存在,或是code所依赖的后面的code.o文件的文件修改时间要比code这个文件新,那么,他就会执行后面所定义的命令来生成code这个文件。
- 如果code所依赖的code.o文件不存在,那么make会在当前文件中找目标为code.o文件的依赖文件,如果找到则再根据上面的规则生成code.o文件。(这有点像一个堆栈的过程)
- 这就是整个make的依赖性,make会一层又一层地去找文件的依赖关系,直到最终编译出第一个目标文件。
- 在找寻的过程中,如果出现错误,比如最后被依赖的文件找不到,那么make就会直接退出,并报错,而对于所定义的命令的错误,或是编译不成功,make根本不理。
- make只管文件的依赖性,即,如果在我找了依赖关系之后,冒号后面的文件还是不在,那么对不起,我就不工作啦。
🌂大白话解析:
make指令后,会进入到Makefile文件中去找到第一个目标文件,也就是code文件,然后发要生成code文件,但是code文件依赖的test.o文件不存在或则,那么就会向下寻找test.o文件,发现要生成的test.o文件的test.s文件也不存在,就会向下找test.s文件,又发现生成test.s文件的test.i文件不存在,向下找test.i文件,这时,生成test.i文件依赖的test.c文件存在,就会执行下面的指令,生成test.i文件,然后一直向上执行,直到最后生成code目标文件。
🌂注意:
再执行make指令的时候,如果源文件在上次执行后到现在,内容没有发生实质性的变化,那么就make就不会执行。
🌂扩展知识:
思考:make和Makefile怎么知道生成的code文件是不是最新的呢?
这里是通过对比时间知道的。 (对比<Modify的时间)
一个文件有三个时间,可以通过指令查看:
# stat 文件
🌂注意:
- 在我们更改内容的时候,往往Modify与Change会发生联动变化,因为内容更改可能会影响文件属性(文件大小)的变化。
- 当我们每次去访问一个文件,该文件的Access时间可能不会改变,取决于Linux系统自己的评判标准,那为什么呢?这个就要谈谈Linux历史了,Linux最开始是每次访问过后,文件的Access时间都会改变,但是后面人们发现,在使用Linux的时候,有时候会经常去查看文件,文件属性(时间)也是数据,如果每次都要对时间进行更新的话,那就意味着每次都会涉及到让操作系统向对应的磁盘文件当中的文件属性Access时间进行更改,就会降低效率。
🌂怎么更新这3个时间;
使用命令:
# touch 文件名 //如果该文件存在就会更新时间,不存在就会创建
🌂项目清理
工程是需要被清理的,可以使用在makefile文件中添加clean,或则自己命名。
像clean这种,没有被第一个目标文件直接或间接关联,那么它后面所定义的命令将不会被自动执行,不过,我们可以显示要make执行。即命令——“make clean”,以此来清除所有的目标文件,以便重编译。
但是一般我们这种clean的目标文件,我们将它设置为伪目标,用 .PHONY 修饰(后面会再次提到),伪目标的特性是,总是被执行的。
示例:
🌂make/Makefile的语法补充
🌂语法一:.PHNOY 文件名
示例:
运行测试:
但是我们一般不会将目标文件设置为伪目标,一般建议将clean设置为伪目标。
🌂不将源文件设置为伪目标的原因:
如果源文件里面很多的源文件,那么如果将该源文件设置为伪目标后,每次make执行编译的时候,都会将所有文件,不管改没改变,都重新编译一遍,会导致效率低下的问题。
🌂语法二:$@ 与 $^
测试:结果:与之前的效果一样。
🌂语法三:makefile里面可以定义变量
例如:
测试: