1、认识make/Makefile
平时在Linux下写C/C++代码代码是,是否总会遇到一个问题:
对于我们写好的一个code.c
、code.cpp
文件,我们想要运行的时候,必须要通过gcc、**g++**来编译
这就导致每次都需要输入以下代码,才能生成对应的可执行文件:
gcc -o code code.c
g++ -o code code.c
对于小工程这样写自然没有问题,但是如果这个工程的文件有
main.c、stack.c、string.c、test.h、queue.c......
呢?
那岂不是每次修改了任意一个文件的内容都要重新写一遍
gcc main.c、stack.c、string.c、test.h、queue.c...... -o code
所以就提供了Linux项目自动化构建工具-make/Makefile
从而对于以上的代码:只需要一个make
指令就可以完成编译,又只需要一个make clean
指令就可以完成清理
1、makefile的最大好处就是自动化编译,对于任何代码,只要makefile写好,只需要一个make指令,整个工程就完成了编译
2、make是一条指令,makefile是一个文件
2、如何写一个正确的makefile文件
对于代码code.c
#include<stdio.h>
int main()
{
int x=1;
int y=2;
printf("%d\n",x+y);
return 0;
}
想要将code.c编译生成可执行文件code,makefile内容如下
- 第一、二行
code:code.c
左侧的code是目标文件,右侧的code.c是依赖文件 – 简单来说:生成code需要code.c文件
gcc -o code code.c
需要执行的指令,code是目标文件,code.c是依赖文件
- 第四、五行
clean:
由于这个clean是对目标文件的清理,所以不需要依赖项(依赖项为空),则冒号右侧可以不写
- 第三行
.PHONY:clean
我们先将.PHONY修饰的clean换成code.c看下效果
发现它提示:code已经是最新的了。所以我们这使得make指令没有执行(因为系统判定他是最新的)。
如果加上.PHONY呢?
发现他任会继续执行make,创建一个code文件。
.PHONY的作用是:修饰一个目标,使其变成伪目标,不论如何,该目标永被执行
注意:日常使用中,习惯用.PHONY修饰clean目标,因为clean可能会因为一些意外导致不能执行,所以要加上.PHONY来确保他永远执行。因为如果拿他来修饰要生成的工程文件(code),那如果不小心又输入了make,那么可能有些他人临时修改的代码,还没经调试就编译了,很容易出错
3、make执行不成功的原因 – 判别文件新旧
若你的make没有用.PHONY修饰,则有时候你会发现又如下提示
make: 'code' is up to date.
这是因为系统认为从之前生成code文件后,你的code的依赖文件没有任何变化,所以就不需要执行make指令
那么系统是怎么看出来code的依赖文件是最新的呢?
$ stat 文件名
Modify:文件内容的修改会导致该时间发生变化
Change:文件属性(创建时间,大小,格式…)的修改会导致该时间发生变化
而系统就会跟据code.c的修改时间,和你生成的目标文件的时间比较,来确认这个code是不是最新的
注意:这是makefile的特性(如果文件没有更新,便不让你make),对于gcc,不管你怎么编译,他都不会提示make: 'code' is up to date.
4、改进makefile内容
先理解一下make原理:
- make会在当前目录下寻找名为“makefile”或“Makefile”的文件
- 将到的makefile文件中的第一个目标文件,作为整个makefile的最终生成文件
- 如果该目标文件的依赖文件不存在,则他会继续往下找看有没有能生成这个依赖文件的依赖文件的依赖文件
- 如果最终死活找不到,那就放弃咯
1)减少makefile的代码量
对于上述代码
$@
:这里的@代表目标文件
$^
:这里的^代表所有依赖文件
2)进行多文件的编译
将同一个文件夹下的三个文件编译链接,对应的makefile如下
因为头文件用include包含了,然后在预处理阶段会展开头文件,所以就没有放进makefile里面编译
上述的过程大致如下:
- 需要生成整个makefile的究极目标文件
code
,但是发现缺少了依赖文件test.o``main.o
,于是需要向下找- 然后用
test.c
生成了test.o
,用main.c
生成了main.o
- 最后递归返回,这时code的依赖文件存在了,就生成了目标文件
code