第15课 - make的隐式规则(上)
1. 问题
如果把同一个目标的命令拆分的写到不同地方,会发生什么?
执行make all
这个实验表明了:如果同一个目标的命令拆分的写到不同地方,那么 make 会覆盖之前的目标对应的命令,使用最新出现的目标对应的命令。
makefile 中出现同名目标时
— 依赖:
-
-
- 所有的依赖将合并在一起,成为目标的最终依赖
-
— 命令:
-
-
- 当多处出现同一目标的命令时,make 发出警告
- 所有之前定义的命令被最后定义的命令取代
-
注意:当使用 include 关键字包含其它文件时,需要确保被包含文件中的同名目标只有依赖,没有命令;否则,同名目标的命令将被覆盖!
target 的下一行,以 tab 开头,该行也会被当做一条空命令。
下面的示例代码就是当主makefile包含了其它makefile导致目标重名,引发了 bug。
2. 什么是隐式规则(built-in rules)?
(1)make 提供了一些常用的,例行的规则实现
(2)当相应目标的规则未提供时,make 尝试使用隐式规则
思考:下面的 makefile 能成功编译吗?为什么?
对应的源文件如下:
1 #include <stdio.h> 2 3 extern void foo(); 4 5 int main() 6 { 7 foo(); 8 9 return 0; 10 }
1 #include <stdio.h> 2 3 void foo() 4 { 5 printf("void foo() : %s\n", "Hello World"); 6 }
1 SRCS := $(wildcard *.c) 2 OBJS := $(SRCS:.c=.o) 3 4 app.out : $(OBJS) 5 $(CC) -o $@ $^ 6 $(RM) $^ 7 @echo "Target ==> $@"
执行 make app.out 成功得到 app.out 可执行程序。
这个 Makefile 中没有 .o 中间文件对应的规则也没有定义 CC 和 RM 变量,但是 make 成功执行并且生成了最终的 app.out 这个可执行程序。
这表明了 make 调用了隐式规则中的 cc -c -o xx.o xx.c 以及 CC 和 RM 变量。
修改上面的Makefile
1 SRCS := $(wildcard *.c) 2 OBJS := $(SRCS:.c=.o) 3 4 # 这里将 cc 改为 gcc 5 CC := gcc 6 7 app.out : $(OBJS) 8 $(CC) -o $@ $^ 9 $(RM) $^ 10 @echo "Target ==> $@" 11 12 # 这里手动添加规则,进行验证 13 %.o : %.c 14 @echo "my rule" 15 $(CC) -c -o $@ $^ 16
执行 make app.out 后的输出,这就验证了之前的隐式规则。
3. 总结上面实验的隐式规则
(1)make 提供了生成目标文件的隐式规则
(2)隐式规则会使用预定义变量完成编译工作
make 中的 .VARIABLES 预定义变量中包含了 make 的其它预定义变量
echo "$(.VARIABLES)"
(3)改变预定义变量将部分改变隐式规则的行为
(4)当已经存在自定义规则时,不再使用隐式规则
注:本文整理于《狄泰12月提升计划》课程内容