Makefile学习(一)- 基础规则
一、简介
Makefile是一种用于自动化编译和构建程序的配置文件,广泛应用于 C/C++ 等项目的构建过程。它通过定义 “规则” 来指定文件之间的依赖关系和编译命令,让make工具能够自动判断哪些文件需要重新编译,从而提高开发效率。
核心作用
自动化构建:无需手动输入冗长的编译命令(如 gcc -o program file1.c file2.c ...
),只需执行 make
命令即可完成整个项目的编译。
增量编译:只重新编译修改过的文件及其依赖项,而非整个项目,大幅节省时间(尤其适合大型项目)。
统一管理:将项目的编译规则、依赖关系、清理操作等集中在一个文件中,便于维护。
Makefile最基本的语法规则为:
目标(target): 依赖(prerequisites)命令(command)
- 目标:通常是要生成的文件(如可执行文件、
.o
目标文件),也可以是 “伪目标”(如clean
,用于定义清理操作)。 - 依赖:生成目标所需要的文件(如源代码、
.h
头文件)。 - 命令:生成目标的具体操作(如编译命令),必须以 Tab 键开头(不能用空格)。
二、实例
创建a.c、b.c文件,内容如下:
##### a.c#include <stdio.h>extern void func_b(void);int main(void)
{printf("this is a\r\n");func_b();return 0;
}
##### b.c#include <stdio.h>void func_b(void)
{printf("this is b\r\n");
}
gcc
如果不用Makefile文件,可以使用gcc指令进行编译。
gcc -o test a.c b.c
可以看到,最终生成的应用程序执行正常。
这里需要注意的是,实例中只使用了a.c和b.c两个文件,所以使用gcc指令可以直接进行编译。但是一个正常的项目,文件通常有几百上千个文件,如果用gcc指令,那么命令将会非常长,例如gcc -o test a.c b.c c.c d.c..............1000.c。显然这种方式是不现实的。
第二点,使用gcc将会编译、链接所有的.c文件。如果只修改了一个.c文件,还使用gcc指令的话,将会把所有.c文件重新编译、链接一遍,那么短则半小时,长则几个小时。所以,如果使用gcc指令直接编译,效率是非常低的。所以,这里需要了解另外一个文件“.o”文件。
在 C/C++ 等编译型语言的项目构建流程中,.o
文件处于中间环节,生成可执行文件的具体流程如下:源代码(.c/.cpp)
→ 编译器编译 → 目标文件(.o)
→ 链接器链接 → 可执行文件。
Makefile
接下来,编写Makefile文件来实现上面的功能。
test: a.o b.ogcc -o test a.o b.oa.o: a.cgcc -o a.o -c a.cb.o: b.cgcc -o b.o -c b.c
根据Makefile的规则“目标(target): 依赖(prerequisites)”可以看到,目标是“test”,依赖“a.o b.o”。而a.0依赖a.c,b.o依赖b.c。当执行make指令的时候,编译器会去对比依赖文件和目标文件的时间。如果依赖比目标新,则会重新生成目标。所以当执行make指令的时候,流程如下:
生成test目标文件,发现依赖a.o b.o。发现a.o和b.o没有且a.o依赖a.c,b.o依赖b.c。所以会先执行gcc -o a.o -c a.c来生成a.o和b.o。然后执行gcc -o test a.o b.o生成test文件。
如果又修改了b.c,make时编译器发现b.c比b.o新,所以需要重新执行gcc -o b.o -c b.c。而a.o比a.c新,所以不需要重新gcc -o a.o -c a.c。
可以看到,最终的可执行文件test运行正常。并且在当前文件夹下生成了a.o和b.o两个中间文件。
这时候,可能会有疑问,为什么不能这么写呢?
a.o: a.cgcc -o a.o -c a.cb.o: b.cgcc -o b.o -c b.ctest: a.o b.ogcc -o test a.o b.o
这样的话,就会先生成.o文件,最后直接再生成可执行文件test。
真的是这样吗?执行一下。
发现并没有生成test,而是只生成了a.o。为什么呢?
Makefile默认将第一个规则的目标作为“默认目标”。上述写法,make会认为a.o就是默认目标,生成a.o后就不会再往下执行了。如果想生成test,必须手动指定目标,执行make test命令,工具才会按照依赖关系先处理a.o和b.o,再生成test。
按照这个思路,如果想清除生成的文件,可以在Makefile文件中增加如下命令:
clean:rm -f *.o test
需要清除是,执行make clean指令。