Makefile
- Makefile概要
- 为啥要使用Makefile
- Makefile的使用
- Makefile的语法(重点)
- Makefile实际使用(重点)
- 利用Makefile删除
- 详解Makefile指令(重点)
- Makefile多命令选项
- Makefile的选择编译特性
- 强制执行
- 总结
- Makefile中变量的使用
Makefile概要
Makefile是一个文件,他是一个工程文件的编译规则。好的Makefile文件可以使用一行命令来完成“自动化编译”,极大提高工作效率。
为啥要使用Makefile
假设我这有两个源代码文件main.c 及 myadd.c,需将其两个编译成一个可执行程序,因为main.c 中调用了 myadd.c中的函数。
正常我们会向下图一样先gcc -c myadd.c -o myadd.o 使其形成汇编代码 。再gcc myadd.o main.c -o a.out 使其两个源文件编译并链接起来形成可执行程序
从上图可以看出两个源文件一起编译形成可执行程序需要两步,并且指令较长。当我们遇到几个甚至几十个源文件一起编译时这将是一个令人头疼的苦差,中途还可能把指令输错。
Makefile的使用
这时候Makefile的作用就体现出来了,我们先在要编译的源文件目录下建立一个Makefile文件(注意不是目录)。
操作如下:
然后再用文本编辑器在Makefile文件中写好指令,在这我用的是vim。如下图在文件中写好指令(现在先不用知道为啥先跟着打上一会会解释)
写好后保存并退出vim,在命令行输入make程序就能自动编译了,非常方便快捷。
Makefile的语法(重点)
如下图假设我们要用Makefile工具,编译main.c
如上图(我已经提前创建好了)先在要编译的源文件目录下建立一个Makefile文件(注意不是目录)。
在编辑Makefile前我们应该定三个前提
1:最终要形成的目标文件名
2:目标文件由什么文件编译得来
3:编译命令是什么
并且Makefile基本规则如下
要形成目标文件名 :源文件
<tob> 命令
实际解释如下图,main 是要形成的目标文件main,main.c 是源文件(也被称为main 的依赖文件),gcc -o main main.c是命令,并且语法规定命令前必须以 tob键 开头。
编辑完成后保存并退出即可,在命令行输入make即可自动编译
Makefile实际使用(重点)
在实际中,我们可能会遇到多个源文件一起编译的情况。下面演示用Makefile工具编译三个源文件,更多的情况也是同一个思路大家放心。
假设我的三个源文件分别是以下三个
main.c
#include"my.h"
int main()
{
int i = add(3,6);
print(i);
return 0;
}
add.c
#include"my.h"
int add(int x , int y)
{
return x + y ;
}
print.c
#include"my.h"
void print(int x)
{
printf("%d\n",x);
}
要用Makefile编译这三个源文件,首先思想是先让这三个源文件都形成汇编代码后再将其链接起来,gcc中 -E是预编译选项,-S是编译选项,-c是汇编选项。这里我们需要得到汇编所以用到 -c 选项,链接直接gcc 及所有要连接代码即可
确定思想后我们开始编辑Makefile如下
Makefile也是自上而下读取数据的,但执行顺序可能不同。
比如上图编译三个源代码时由于第一条,需要具有main.o print.o add.o三个文件才能编译成a.out文件(目标文件是main.o,源文件是main.o print.o add.o)显然这个条件并不满足。所以Makefile会先把第一条指令保存起来,先执行下面已经满足条件的代码,直到条件满足时才会执行(具有main.o print.o add.o三个文件)
第二条指令,要求文件中有main.c文件,显然我们是满足条件的,所以执行了gcc -c main.c -o main.o命令,同时也生成了main.o文件
第三条指令,要求文件中有print.c文件,显然我们是满足条件的,所以执行了gcc -c print.c -o print.o命令,同时也生成了print.o文件
第四条指令,要求文件中有add.c文件,显然我们是满足条件的,所以执行了gcc -c add.c -o add.o命令,同时也生成了add.o文件
这个时候我们显然已经满足了第一条指令的要求,有了main.o print.o add.o三个文件。所以执行gcc main.o add.o print.o -o a.out命令并生成了a.out文件
注意:如果Makefil文件中其他指令都执行完了依然有一条指令不满足条件而无法执行,Makefile将会报错,说明指令的依赖关系设置有误
成果演示:
利用Makefile删除
读完上述内容已经可以利用Makefile实现自动编译了,但是编译过程中产生了汇编文件main.o print.o add.o,我只想要最终的啊a.out文件。所以每次编译后我需要一一删除异常麻烦。
其实Makefile能设置很多功能,其中实现自动删除目标文件也是不在话下的
只要我们在Makefile加上
clean:
rm main.o print.o add.o
即可。
保存并退出后 ,命令行输入Makefile clean即可删除main.o print.o add.o三个文件
详解Makefile指令(重点)
有人看到这肯定说,为啥编译用make作为指令,删除用make clean作为指令
其实make命令是默认执行Makefile文件中的第一条指令,及其相关指令。
比如我把Makefile中代码换一下,执行大家就明白了
代码更改后我们依然输入make,但这次只生成了main.o文件说明只执行了Makefile中的第一行代码。
上面已经证实了make命令是默认执行Makefile文件中的第一条指令,然后Makefile的命令规则为
make [命令选项]
命令选项是目标文件名,虽然clean不会生成文件但我们也可以把他看做成目标文件名
如下图框框中的都是命令选项
实际使用
如下动图我演示了指令有
1:make add.o
2: make print.o
3: make main.o
4: make clean
5: make a.out
动图较长大家忍一下
Makefile多命令选项
并且可以同时有多条命令选项
如: make a.out clean
作用:(在我这个Makefile下)执行a.out选项命令编译链接完代码后,执行clean选项命令(把不需要的汇编代码删除);
如下图
上述说明Makefile非常强大,可以有很多条编译指令,并且互不影响。
Makefile的选择编译特性
在实际工程中代码的编译时间通常比较长,如果重复性编译这会浪费很多时间。所以Makefile在编译前都会检查代码较上次编译是否发生过更改,如果没有将不会编译次代码,如下图。
如下图,在多文件编译中,Makefile依然只会编译修改后的源文件,未修改的并不会重新编译,这大大节省了编译时间(如果是几十个源文件甚至更多的工程呢,仅仅是区分就令人头疼了)
强制执行
上面说了Makefile是有自己想法的,可以选择性编译(执行)。
但我就想他每次必须执行,我不需要他又想法。那使用 .PHONY 修饰即可
如下图
如下图加完之后,就能每次都执行了(强制),不会出现选择性执行的情况。
总结
1:命令行必须以键开通
2:目标文件与依赖文件之间需以 :号隔开
3:Makefile能有多条指令
4:Makefile编译完成后,后期有代码更新Makefike能针对被修改的源文件单独编译并链接。
Makefile中变量的使用
如下图main.o print.o add.o比较长,每次都要打比较繁琐。
针对这个问题Makefile可以定义变量来简化他,比如下图使DATA 等于main.o print.o add.o
定义方法:变量名 = 字符串(各文件名等)
使用方法:${变量名}
使用效果
优点:变量的定义能简化复杂且重复的数据使代码美观,编写方便。
变量的基本语法
1.变量与变量内容以= 号隔开,同时两边可以具有空格
2.变量左边不可以有,例如上面范例的第一行DATA左边不可以是
3.变量与变量内容在 = 号两边不能具有 : 号
4.在习惯上,变量名最好是以大写字母为主;
5.运用变量时,以 变量或 {变量}或 变量或 (变量)使用;