隐含规则为make提供了一类目标文件通用方法,不需要在makefile中明确的给出重建特定目标文件所需的细节描述。
只要目标文件中除后缀以外其他部分相同,make都能够使用若干隐含规则来最终产生这个目标文件。
对应关系:
EXENAME.o 对应 EXENAME.c
EXENAME 对应 EXENAME.o
1.隐含规则的使用
foo:foo.o
cc -o foo foo.o $(CFLAGS) $(LDFLAGS)
这里并没有给出重建文件foo.o的规则,在make执行这条规则的时候,无论foo.o存在与否,都会试图根据隐含规则来重建这个文件。
可以使用 -r 或者 -R 参数取消隐含规则
2.常用隐含规则
编译c程序:
N.o 自动由 N.c 生成,执行命令 $(CC) -c $(CPPFLAGS) $(CFLAGS)
链接单一的object文件
N 自动由 N.o 生成,执行命令 $(CC) $(LDFLAGS) N.o $(LOADLIBES) $(LDLIBS)
3. 隐含变量
内嵌隐含变量的命令中,所使用的变量都是预定义的变量,我们称之为隐含变量。
在makefile中,通过命令行参数或者设置系统环境变量来对它进行重定义。
隐含规则中所使用的隐含变量分为两类:
- 代表一个命令的名字。
- 代表执行这个程序使用的参数。
3.1 代表命令的变量
AR 函数库打包程序,可以创建静态库.a文档,默认是 ar
AS 汇编程序,默认 as
CC c编译程序,默认是cc
CPP c程序的预处理器,默认是 $(CC) -E
YACC yacc文法分析器,默认命令是 yacc
RM 删除命令, 默认是rm -f
3.2 代表参数的变量
ARFLAGS 执行AR命令的命令行参数,默认是 rv
ASFLAGS 执行汇编语器 AS 的命令行参数
CFLAGS 执行CC编译器的命令行参数
YFLAGS yacc文法分析器参数
4. make隐含规则链
如果一个目标文件需要一系列隐含规则才能完成它的创建,则把这个系列称为一个 链。
中间过程文件:
文件N.c不存在也没有在makefile中提及的情况,只要存在N.y这个文件,那么make也会经过这两个步骤来重建N.o :
N.y -> N.c -> N.o
其中,N.c就在中间过程文件。并且会自动加入到依赖关系链中。
在Makefile中明确提及的文件都不被作为中间过程文件来处理。
当中间文件不存在时:
- 对于一个普通文件,因为makefile没有提及,则此文件可能是一个目标的依赖,make在执行它所在的规则前会试图重建它。
- 对于一个中间文件,因为没有明确提及,make不会去试图重建它。除非这个中间文件所依赖的文件被更新。
如果make在执行时需要一个中间过程文件,那么默认的动作是:这个中间过程文件在make执行结束后会被删除。
5. 模式规则
在模式规则中,目标名中需要包含有模式字符 % ,其可以匹配任何非空字符串。
模式字符 % 的匹配和替换发生在规则中所有变量和函数引用展开之后。
普通多目标规则(多目标中没有模式):
- 将每一个目标作为一个独立的规则来处理,所以多个目标就对应多个独立的规则。
多目标模式规则:
- 所有规则的目标 共同拥有 依赖文件和规则的命令行,当文件符合多个目标模式中的 任何一个时,规则定义的命令就有可能将会执行。
- 在执行一次命令之后,规则不会再去检查是否需要重建符合其他模式的目标。
- 当一个目标文件同时符合多个目标模式时,make将会把 第一个 目标匹配的模式规则作为重建它的规则。
- makefile中明确指定的模式规则会覆盖隐含模式规则。
比如有如下 多目标模式 规则:
%.o %.x : %.c
$(CC) $(CFLAGS) $< -o $@
当执行make foo.o foo.c时,会只看到第一个目标foo.o被创建,同时make会提示foo.x文件是最新的,其实foo.x并没有被创建。
6. 自动化变量
自动化变量的取值取决于所执行的规则的目标和依赖的文件名。
有以下自动化变量:
$@ 表示规则的文件名
$% 当规则的目标文件是一个静态库文件时,代表静态库的一个成员名。如果目标不是静态库,其值为空。
$< 规则的第一个依赖文件名。
$? 所有比目标文件更新的依赖文件列表,空格分隔。
$^ 规则的所有依赖文件列表,使用空格分隔。
$+ 类似于$^,但是保留了依赖文件中重复出现的文件。
$* 在模式规则和静态模式规则中,代表 茎,茎 是目标模式中 % 所代表的部分。
$(@D) 表示目标文件的目标部分,不包括斜杠。如果$@是 dir/foo.o 则$(@D) 为 dir
$(@F) 表示目标文件完整文件名中除目录以外的部分。如果$@是 dir/foo.o 则$(@F) 为 foo.o
$(*D)
$(*F) 表示目标 茎 中的目录和文件名部分。
$(%D)
$(%F) 当目标为静态库时,表示库文件成员中目录部分和文件名部分。
$(<D)
$(<F) 表示规则中第一个依赖文件的目录部分和文件名部分。
$(^D)
$(^F) 表示规则中所有依赖文件的目录部分和文件名部分。
$(+D)
$(+F) 表示规则中所有依赖文件的目录部分和文件名部分(可存在重复文件)。
$(?D)
$(?F) 表示被更新的依赖文件的目录部分和文件名部分。
7. 万用规则
当模式规则的目标只有一个模式字符 % ,我们称之为 万用规则。
使用万用规则会导致make执行时考虑的情况变多,从而效率降低,所以需要对万用规则的使用进行限制:
将万用规则设置为最终规则,定义时使用双冒号规则。作为最终规则,此规则只有在它的依赖文件存在时才能被应用。即使它的依赖可以由隐含规则创建也不行。
8.缺省规则
在make执行过程中无法为一个文件找到合适的重建规则,那么就用缺省规则去创建。
比如:
%::
touch $@
执行make时,对所有不存在的.c文件将会使用touch命令创建这样一个空的源文件。