1. Makefile 的引入和规则
Makefile 的主要职责是组织管理程序,组织管理文件。
对于多文件的编译链接生成可执行程序使用 gcc -o test a.c b.c
是可以的,但是当文件多起来这样会很麻烦,而且使用这样的命令会对所有的文件都处理一次,效率会非常低。只修改一个文件,所有的文件都重新处理,编译的时间会非常长。
对于这些源文件,我们可以分别进行编译生成.o 文件最后再进行链接。当修改了一个文件,只需要对这个文件进行编译然后链接就不会重新编译别的文件了。
怎么知道哪些文件被修改了呢?只需要比较时间就可以知道了,比如a.c 的时间比a.o 的时间新,就表明a.c 被修改了,然后对a.c 单独进行编译就好了。Makefile 就是这样的。
makefile 最基本的语法规则是:
目标 : 依赖1 依赖2 ...
[TAB]命令
当“依赖”比“目标”新,就执行他们下面的命令。比如以下 makefile 文件:
test : a.o b.o
gcc -o test a.o b.o
a.o : a.c
gcc -c a.o a.c
a.o : b.c
gcc -c b.o b.c
2. Makefile 的语法
通配符
假如一个目标文件所需要的依赖文件很多,那么就要写很多规则,这显然是不合常理的,这就引出了通配符的概念来解决这些问题。
对于上节的程序可以进行以下更改:
test : a.o b.o
gcc -o test $^
%.o : %.c
gcc -c -o $@ $<
%.o:表示所有的.o 文件
%.c:表示所有的.c 文件
$@:表示目标
$<:表示第一个依赖文件
$^:表示所有的依赖文件
假象目标. PHONY
- 我们想清除文件,只需要在 makefile 文件结尾添加:
clean:
rm *.o test
然后执行 make clean 就行了。
2. 使用 makefile
执行 make[目标]也可以不跟目标名,不跟的话就默认执行第一个目标然后下面的命令。当我们执行 make clean 时会在文件里找 clean 这个目标,当当前目录下没有 clean 这个文件时会执行下面的命令,但当前目录下有 clean 这个文件时由于有 clean 这个文件且没有依赖文件,就无法判断文件的修改时间导致无法执行 make clean 的操作。
解决方法就是把 clean 目标定义为假象目标,用关键字 PHONY
.PHONY: clean //把clean定义为假象目标。就不会判断名为“clean”的文件是否存在
然后在 Makfile 结尾添加. PHONY: clean 语句,重新执行:make clean,就会执行删除操作。
变量
- 简单变量(即时变量):
A : xxx # A的值即刻确定,在定义时即确定
对于即使变量使用 “:=” 表示,它的值在定义的时候已经被确定了。
- 延时变量
B = xxx # B的值使用时才确定
对于延时变量使用“=”表示。它只有在使用到的时候才确定,在定义/等于时并没有确定下来。
想使用变量的时候使用“$”来引用,如果不想看到命令是,可以在命令的前加上"@"符号,就不会显示命令本身。当我们执行 make 命令的时候,make 这个指令本身,会把整个 Makefile 读进去,进行全部分析,然后解析里面的变量。常用的变量的定义如下:
:= # 即时变量
= # 延时变量
?= # 延时变量, 如果是第1次定义才起效, 如果在前面该变量已定义则忽略这句
+= # 附加, 它是即时变量还是延时变量取决于前面的定义