问题
如果同一个目标的命令拆分写到不同地方,会发生什么?
下面的程序怎么执行?为什么?
makefile 中出现同名目标时
依赖:
- 所有的依赖合并在一起,成为目标的最终依赖
命令:
- 当多处出现同一目标的命令时,make 发出警告
- 所有之前定义的命令被之后定义的命令取代
注意事项
当使用 include 关键字包含其他文件时,需要确定被包含文件中的同名目标只有依赖,没有命令;否则,同名目标的命令将被覆盖!
命令的拆分
makefile
.PHONY : all
var := test_var
all :
@echo "this is $(var)"
include 1.mk
1.mk
.PHONY : all
all :
@echo "this is command from 1.mk"
include 将 1.mk 文件内容包含进来后,当前 makefile 中 all 目标对应的命令定义在2个不同的地方,前面 all 所定义的命令会被后面定义的命令所取代。
执行结果如下所示:
make 首先发出警告,随后执行后面定义的 all 的命令。
什么是隐式规则 (built-in rules)
make 提供了一些常用的,例行的规则实现
当相应目标的规则未提供时,make 尝试使用隐式规则
下面的 makefile 能编译成功吗?为什么?
初探隐式规则
make 提供了生成目标文件的隐式规则
隐式规则会使用预定义变量完成编译工作
改变预定义变量将部分改变隐式规则的行为
当存在自定义规则时,不再使用隐式规则
初探隐式规则
makefile
SRCS := $(wildcard *.c)
OBJS := $(SRCS:.c=.o)
TARGET := app.out
CC := gcc
all :
@echo "$(.VARIABLES)"
$(TARGET) : $(OBJS)
$(CC) -o $@ $^
$(RM) $^
@echo "succsee target => $@"
%.o : %.c
$(CC) -o $@ -c $^
在执行 make 的时候,make 发现我们并没有给 .VARIABLES 和 RM 变量赋值,所以 make 会通过隐式规则使用预定义变量完成编译工作。
深入理解隐式规则
当 make 发现目标的依赖不存在时
- 尝试通过依赖名逐一查找隐式规则
- 并且通过依赖名推导可能需要的源文件
隐式规则的副作用
编译行为难以控制
- 大量使用隐式规则可能产生意想不到的编译行为
编译效率低下
- make 从隐式规则和自定义规则中选择最终使用的规则
隐式依赖链
当依赖的目标不存在时,make 会极力组合各种隐式规则对目标进行创建,进而产生意料之外的编译行为!
问题
makefile 提供了多少隐式规则?如何查看隐式规则?
查看隐式规则
查看所有:make -p
查看具体规则:make -p | grep "XXX"
深入理解隐式规则
makefile
app.out : main.o func.o
$(CC) -lstdc++ -o $@ $^
当前目录下的文件如下所示:
app.out 依赖于 main.o 和 func.o,make 发现当前 makefile 中没有生成 main.o 和 func.o 的规则,所以 make 会使用隐式规则,尽力生成 main.o 和 func.o
执行结果如下所示:
make 使用了隐式规则尽力去生成目标的依赖。
隐式规则的禁用
局部禁用
- 在 makefile 中自定义规则
- 在 makefile 中定义模式 (如:%.o:%.p)
全局禁用
- make -r
后缀规则简介
后缀规则是旧式的 "模式规则"
可以通过后缀描述的方式自定义规则
双后缀规则
定义一对文件后缀 (依赖文件后缀和目标文件后缀)
- 如:.cpp.o <=> %.o : %.cpp
单后缀规则
定义单个文件后缀 (源文件后缀)
- 如:.c <=> % : %.c
关于后缀表达式的注意事项
后缀规则中不允许有依赖
后缀规则必须有命令,否则无意义
后缀规则将逐步被模式规则取代
后缀规则初体验
makefile
app.out : main func.o
$(CC) -lstdc++ -o $@ $^
.c.o :
@echo "my suffix rule"
$(CC) -o $@ -c $^
.c :
@echo "my suffix rule"
$(CC) -o $@ -c $^
当前目录下的文件如下所示:
执行结果如下所示:
可以看出 main 是由当前 makefile 的后缀规则创建出来的,但是当前 makefile 没有生成 func.o 的规则,所以 make 使用隐式规则去生成 func.o。