目录
要实现一个大型的工程需要的源文件数量是非常多的,并且这些源文件的类型、功能、编译顺序都是特定的,所以需要makefile来定义了一系列的规则来指定,文件的编译顺序以及那些文件需要重复编译,有些还需要执行更复杂的操作,makefile 就像一个 Shell 脚本一样,其中也可以执行操作系统的命令。 makefile写好后,只需要执行一个 make 命令,整个工程完全自动编译,可以大大提高开发的效率。
一.程序的编译和链接
我们最终需要的是文件,首先需要将源文件编译生成为中间文件(*.o),这个过程叫编译,编译成功的条件是语法正确,变量和函数的声明正确;然后需要链接器把这些中间文件链接合成一个可执行文件,但由于源文件太多,编译生成的中间目标文件太多,而在链接时需要明显地指出中间目标文件名,这样操作会很不方便,所以,我们要给中间目标文件打个包,在 Windows 下这种包叫“库文件”(Library File),也就是 .lib 文件,在 UNIX 下,是 Archive File,也就是 .a 文件。
二.Makefile核心规则
target... : prerequisites ...
command
...
...
-------------------------------------------------------------------------------
target:是我们想要的文件,它可以是一个目标文件,可以是.o文件,也可以是执行文件等等。
prerequisites:要生成target所依赖的文件或是目标。
command:想要完成我们的目标所需要的执行的命令。(任意的Shell命令)
三.一个简单的例子
在工程中如果项目很大的话,编译是很费时间的,而如果我们每次修改完代码进行调试的时候都需要重新编译的话就更费时间了,所以我们要做的是第一次把所有源文件编译好,生成.o文件,后面如果有修改某些源文件的话,我们只编译被修改的文件就好了,然后再链接即可。如果是头文件被修改,那么所有引用该头文件的源文件也要重新编译一下。
假如这里有一个三个文件main.c ,test1.c,test2.c,main.c的实现依赖于后面二者。如果我们要写makefile的话就是:
main:main.o test1.o test2.o
gcc -o main main.o test1.o test2.o
main.o:main.c
gcc -c main.c
test1.o:test1.c
gcc -c test1.c
test2.o:test2.c
gcc -c test2.c
clean:
rm *.o
rm main
(注意:命令行必须以tab键开始,而不是空格)
make的工作原理是:先查看当前文件下有没有实现目标文件的依赖文件,如果没有,就在下面的代码的目标文件中找,有就执行相应的代码。
1)make会在当前目录下找名字叫“Makefile”或“makefile”的文件。
2) 如果找到,它会把文件中的第一个目标文件(target),在上面的例子中,他会找到“main”这个文件,并把这个文件作为最终的目标文件。
3) 如果main文件不存在,或是main所依赖的后面的 .o 文件的文件修改时间要比mian这个文件新,那么,他就会执行后面所定义的命令来生成mian这个文件。
4) 如果main所依赖的.o文件也存在,那么make会在当前文件中找目标为.o文件的依赖性,如果找到则再根据那一个规则生成.o文件。
5) 因为.c文件和.h文件都是存在的,所以make会生成 .o 文件,然后再用 .o 文件声明make的终极任务,也就是执行文件main了。
整个过程就是一个依赖关系的找寻,一步一步找,直到最终编译出第一个目标文件(只要第一个目标文件完成编译,make的任务就会结束),期间出错会直接退出;而clean目标文件,没有被第一个目标文件直接或间接关联,所以它后面的命令不会被执行,需要执行时,我们输入make clean即可。
任意一个依赖文件有更新,目标文件都必须更新,
四.Makefile语法
1.Makefile规则格式
如章节三所示
2.Makefile变量
在上述例子中,可以看到main.o,test1.o等等多次被输入,如果把他们定义成简单名称的变量,那么输入工作将得到减少。
#变量定义
objects=main.o test1.o test2.o
main:$(objects)
gcc -o main $(objects)
#为注释的开头;
变量引用的方法为$(变量名)
1)赋值=
@代表不打印执行这条命令的过程
变量的真实值是最后一次有效值;
2)赋值号:=
:=不会使用后面的定义,只会使用前面的定义和=有所区别
3)赋值号?=
如果变量在之前就被赋值了,那就是之前的值,如果变量之前没有被赋值过,就是现在的这个值。
4)赋值号+=
追加赋值
3.模式规则
源文件很多时,一个文件一条规则太麻烦了,在模式规则中,%可以表示任意非空的字符串,类似于通配符,“%.c”表示所有以.c结尾的文件,a.%.c表示以a开头.c结尾的文件
4.自动化变量
自动化变量会把模式(即%形式)中定义的一系列的文件自动的挨个取出,直至所有符合模式的文件都取完,自动化变量只应该出现在规则的命令中,常用的自动化变量如下图(图来自正点原子):
最常用的是$@ $^ $<三个自动化变量
<