Makefile文件定义了一系列的规则来指定哪些文件需要先编译,哪些文件需要后编译,哪些文件需要重新编译,可以实现自动化编译,一旦写好,只需要一个make命令,整个工程完全自动编译,极大的提高了软件开发的效率。
命名为makefile或者Makefile。规则为:
目标....:依赖...
命令(Shell命令) //(前面有个缩进)
...
目标:最终要生产的文件
依赖:生产目标所需要的文件
命令:通过执行命令对依赖操作生成目标(前面必须Tab缩进)
//fun1.c
void fun1(void) {
printf("this is fun1!\n");
}
//fun2.c
void fun2(void) {
printf("this is fun2!\n");
}
//head.h
#include
void fun1(void);
void fun2(void);
//test.c
#include
#include "head.h"
//main.c
int main(){
//test
fun1();
fun2();
fun1();
return 0;
}
存在这样四个文件, main.c函数里面调用了head.h的两个函数。
vim makefile
创建makefile文件,输入相关编译命令。
app:fun1.c fun2.c main.c
gcc fun1.c fun2.c main.c -o app
make
输入make命令,执行makefile文件,生成可执行文件app。
可以看到,终端会自动执行makefile里面的语句。这里只有一句编译命令,看不出makefile有多方便,但是当大型工程中编译命令有上百行的时候,只需要一句make就可以输出上百行编译命令,就会特别方便。
在执行命令之前,需要先检查规则中的依赖(红色框)是否存在。如果存在,执行命令;如果不存在,向下检查其他规则,检查是否存在一个规则用来生成该依赖,如果找到了,则执行该规则中的命令。看下面这样一个例子(版本2)。
.o文件是汇编之后得到的文件,但是还没有进行链接,只有进行了链接才能生成可执行文件。
-c命令能够编译、汇编指定的c文件,生成.o文件,但是不进行链接。
makefile文件一共存在四条规则。当检查第一条规则的依赖时,发现这些.o文件都不存在,就会向下检查其他规则,发现存在规则生成.o文件,所以执行规则中的命令。
通过命令行能发现,make先执行了生成.o文件的下面三条规则,以便生成第一条的依赖,然后再执行第一条规则生成可执行文件。
在执行规则中的命令是,会比较目标和依赖文件的时间。如果依赖的时间比目标的时间晚,需要重新生成目标。如果依赖的时间比目标的时间早,目标则不需要更新,对应规则中的命令不需要被执行。
当我们再次执行make,显示可执行文件app已经是最新的。接下来简单修改下main.c文件,中间随便加点注释,再次执行make。
会发现make命令执行了生成main.o的规则以及生成app的规则。这是因为对于main.o :main.c
,因为main.c发生修改,文件的时间会更新,所以变成依赖main.c的时间比目标main.o的时间晚,需要重新生成目标。对于生成app的规则同理。
所以要合理利用这条规则,可以将编译分为多条规则(上面的版本2)执行,而不是一条规则(上面的版本1)。如果仅有一条规则,只要其中一个依赖发生改变,就会全部重新编译。
预定义变量
自定义变量:变量名=变量值
获取变量的值:$(变量名)
通过修改获得makefile第3个版本,通过定义变量,获取变量。
%.o : %.c
%:通配符,匹配一个字符串;两个%对应的是同一个字符串
当执行第一条规则,发现.o文件不存在,就会去检查下面的规则是否能生成该依赖。对于模式匹配,只要符合条件,就能执行。
第二条模式匹配规则是,将依赖.c文件生成目标.o文件,命令行中 ( C C ) 代 表 获 取 C 编 译 器 , (CC)代表获取C编译器, (CC)代表获取C编译器,<代表获取第一个依赖的名称,$@代表获取目标的完整名称。运行后可以正常执行。
$(wildcard PATTERN...)
功能:获取指定目录下指定类型的文件列表,PATTERN代表目录,如果有多个目标,一般使用空格间隔。
$(patsubst <pattern>, <replacement>, <text>)
功能:查找 中的单词(单词以“空格”、“Tab”、“换行”分隔)是否符合模式,如果匹配,则以替换。
可以包括通配符“%”,表示任意长度的字符串。如果想要实际使用普通的“%”,前面需要加转义字符,“%”。
修改获取第四个版本。对于第一条规则,我们需要的是.o文件,但是.o文件目前还没有生成,所以必须先通过函数获取.c文件,再进行替换获取.o文件。
src变量代表获取当前目录下所以的.c文件,即fun1.c、fun2.c、main.c。
objx变量代表,将刚才获取的src变量(所以.c文件),找到符合%.c的那部分,然后替换成%.o,实际上就是得到了fun1.o、fun2.o、main.o。
重新执行make,运行成功。
通过ls命令可以发现make生成了很多中间.o文件,这些中间文件是为了生成最终的可执行文件,但是生成之后就没啥用的。所以可以加上rm命令删除掉。