1.make/Makefile的重要性
- 会不会写makefile,从一个侧面说明了一个人是否具备完成大型工程的能力
- 一个工程中的源文件不计数,其按类型、功能、模块分别放在若干个目录中,makefile定义了一系列的规则来指定,哪些文件需要先编译,哪些文件需要后编译,哪些文件需要重新编译,甚至于进行更复杂的功能操作
- makefile带来的好处就是——“自动化编译”,一旦写好,只需要一个make命令,整个工程即可完全自动编译,极大的提高了软件开发的效率。
- make是一个命令工具,是一个解释makefile中指令的命令工具,一般来说,大多数的IDE(集成开发环境)都有这个命令,比如:Delphi的make,Visual C++的nmake,Linux下GNU的make。可见,makefile都成为了一种在工程方面的编译方法。
-
make是一条命令,makefile是一个文件(在当前源代码的路径下),两个搭配使用,完成项目自动化构建。
2.规则及使用
使用
我们先来看一下make/Makefile在Linux中的简单使用(先看看猪跑,接着会解析规则):
第一步
:我们先创建一个myfile.c文件,写入简单的内容
第二步
:创建一个Makefile文件,写入符合Makefile规则的内容
第三步
:使用make命令,生成可执行程序,使用make clean删除可执行程序
规则
Makefile是一个围绕依赖关系和依赖方法构建的一个自动化编译的工具。
1.
依赖关系
:在这个程序中,myfile可执行程序和myfile.c文件构成依赖关系,myfile.c的改变会影响myfile,所以myfile依赖于myfile.c。所以
第一行就表示myfile可执行程序的生成依赖于myfile.c文件。
2.
依赖方法
:myfile可执行程序的生成依赖于myfile.c,
而
gcc myfile.c -o myfile
就是myfile文件依赖myfile.c的依赖方法。
(
注意:完成一件事必须要有正确的依赖关系+正确的依赖方法。
)
3.PHONY:被该关键字修饰的对象是一个伪目标,即该目标可以总是被执行(不需要进行时间新旧的比较),即如果我们希望多次生成一样的可执行程序,就可以用这个关键字修饰对象,不过我们一般不这样操作。大家肯定会有疑问:“啊?总是被执行是什么意思?”
我们接下来以这个Makefile文件为例,myfile.c文件的内容还是不变的。
make原理
:这段代码,充分体现了依赖关系与依赖方法:make会在当前目录下找名字为“Makefile”或“makefile”的文件,然后找到第一个依赖关系,myfile的生成依赖于myfile.o,myfile.o的生成依赖于myfile.s,myfile.s的生成依赖于myfile.i,myfile.i的生成依赖于myfile.c,然后gcc的内容分别是它们的依赖方法。然后clean就是清理,当我们在命令行输入make clean,就会执行
rm -f myfile myfile.i myfile.o myfile.s
这句指令,就可以直接删除这些文件了。这就是整个make的依赖性,make会一层又一层地去找文件的依赖关系,直到最终编译出第一个目标文件。在找寻的过程中,如果出现错误,比如最后被依赖的文件找不到,那么make就会直接退出,并报错,而对于所定义的命令的错误,或是编译不成功,make根本不理。make只管文件的依赖性,即,如果在我找了依赖关系之后,冒号后面的文件还是不在,那么对不起,我就不工作啦。
项目清理
:工程是需要被清理的。
像clean这种,没有被第一个目标文件直接或间接关联,那么它后面所定义的命令将不会被自动执行,不过,我们可以
显示要make执行。即命令——“make clean”
,以此来清除所有的目标文件,以便重编译
。但是一般我们这种clean的目标文件,我们将它设置为伪目标,用 .PHONY 修饰,伪目标的特性是,总是被执行的。
这段代码第一次执行make,可以正常执行,然鹅,我们第二次在命令行输入make,就无法再次被执行了。然鹅,大家看上图make clean被执行一次生效之后,我们再执行一次,还是可以生效。那么这就是.PHONY的作用,也就是“总是被执行”的意思。如果大家希望make指令可以总是被执行,那么就在开头加上.PHONY。那么在不加.PHONY,gcc是怎么知道我们不需要再编译了呢?
方法:如果我们make之后,又对源文件进行修改,则我们还可以再执行make指令(即编译器会判断myfile.c的modify时间是否早于myfile可执行程序,如果晚于myfile,则说明myfile.c文件发生修改,make可以继续执行,生成新的程序,覆盖旧的程序)。
注意
:
make是一条命令,makefile是一个文件(在当前源代码的路径下),两个搭配使用,完成项目自动化构建。make指令默认执行Makefile文件中第一个依赖方法。如果你想运行指定的程序,就要显示定义,例如上述的make clean。
例如我们将Makefile文件改成如下代码并wq退出,在命令行输入make指令,就会先执行rm指令。
3.Makefile编译多文件
当我们的工程中有多个源文件的时候,我们要如何进行编译?
首先,我们可以直接使用gcc指令对多个源文件进行编译,进而生成可执行程序。注意用这种方式编译文件,不需要加上头文件,因为编译器通过源文件的内容可以直接知道所需头文件的名字。
但进行多文件编译的时候,一般不直接用gcc生成可执行程序,而是先用每个源文件生成各自的二进制文件,即.o文件,然后再将这些二进制文件通过链接生成可执行程序。但是随着源文件个数的增加,指令长度也会增长,所以我们就需要用到项目自动化构建工具make/Makefile,这样可以大大提高编译运行的效率。
原因
:
- 如果直接使用源文件生成可执行程序,那么若有一个.c文件发生了修改,我们再生成可执行文件就需要将之前的所有源文件重新进行编译链接。
- 如果每个源文件先生成自己的.o目标文件,那么一个源文件被修改,我们就只需要重新编译该源文件的二进制文件,然后将所有二进制文件进行链接。这样大大提高了程序编译运行的效率。
步骤一
: 在源文件所在目录下创建一个名为Makefile/makefile的文件。
步骤二
: 编写Makefile文件。
执行结果
:
补充:Makefile文件的快捷书写方式
- $@:表示依赖关系中的目标文件(冒号左侧)。
- $^:表示依赖关系中的依赖文件列表(冒号右侧)。
- $<:表示依赖关系中的第一个依赖文件(冒号右侧第一个)。
所以上述文件,还可以写成: