LV02-05-Makefile-04-隐含规则和模式规则
本文主要是makefile——隐含规则和模式规则相关笔记,若笔记中有错误或者不合适的地方,欢迎批评指正😃。
点击查看使用工具及版本
Windows | windows11 |
Ubuntu | Ubuntu16.04的64位版本 |
VMware® Workstation 16 Pro | 16.2.3 build-19376536 |
SecureCRT | Version 8.7.2 (x64 build 2214) - 正式版-2020年5月14日 |
开发板 | 正点原子 i.MX6ULL Linux阿尔法开发板 |
uboot | NXP官方提供的uboot,NXP提供的版本为uboot-imx-rel_imx_4.1.15_2.1.0_ga(使用的uboot版本为U-Boot 2016.03) |
linux内核 | linux-4.15(NXP官方提供) |
STM32开发板 | 正点原子战舰V3(STM32F103ZET6) |
点击查看本文参考资料
参考方向 | 参考原文 |
Makefile | 跟我一起写Makefile |
点击查看所需测试文件
各文件所在目录的结构如下:
1 | . |
1 |
|
1 |
|
1 |
|
1 | void test1Fun(); |
一、隐含规则
1.什么是隐含规则
在我们使用 Makefile 时,有一些我们会经常使用,而且使用频率非常高的东西,比如,我们编译 C/C++ 的源程序为中间目标文件( Unix 下是 [.o] 文件, Windows 下是 [.obj] 文件)。
“隐含规则”就是一种惯例,make 会按照这种“惯例”心照不喧地来运行,即便我们的 Makefile 中没有书写这样的规则。例如,把 [.c] 文件编译成 [.o] 文件这一规则,我们根本就不用写出来, make 会自动推导出这种规则,并生成我们需要的 [.o] 文件。
“隐含规则”会使用一些系统预定义的变量,我们可以改变这些系统变量的值来定制隐含规则的运行时的参数。如系统变量“ CFLAGS ”可以控制编译时的编译器参数。我们还可以通过“模式规则”(后边会说明)的方式写下自己的隐含规则。用“后缀规则”来定义隐含规则会有许多的限制。使用“模式规则”会更回得智能和清楚,但“后缀规则”可以用来保证我们 Makefile 的兼容性。
2.使用隐含规则
我们在测试目录中穿件如下内容的 Makefile 文件:
1 | OBJ = main.o test1.o test2.o |
然后在终端执行 make 命令,会看到有如下输出:
1 | cc -c -o main.o main.c |
由此可以看出,即便我们没有写依赖目标的规则, Makefile 依然帮我们推倒出了所需要的 main.o 、 test1.o 和 test2.o 。前边学习变量的时候笔记中有说明,系统预定义变量中有一个 CC ,它的值就是 cc ,而这里隐含规则的自动推导使用的就是系统的预定义变量了。这已经是“约定”好了的事了, make 和我们约定好了用 C 编译器 cc 生成 [.o] 文件的规则,这就是隐含规则。
如果我们为 [.o] 文件书写了自己的规则,那么 make 就不会自动推导并调用隐含规则,它会按照我们写好的规则忠实地执行 ,如下边的 Makefile :
1 | OBJ = main.o test1.o test2.o |
我们执行 make 命令的话,就会看到如下提示信息:
1 | gcc -c main.c -o main.o |
3.取消隐含规则
我们有时候不想使用隐含规则的话,我们就可以在执行 make 命令的时候加上 -r 参数来取消隐含规则:
1 | make -r |
当然,即使是我们指定了 -r 参数,某些隐含规则还是会生效,因为有许多的隐含规则都是使用了后缀规则来定义的,所以,只要隐含规则中有“后缀列表”(也就一系统定义在目 标 .SUFFIXES 的依赖目标 ),那么隐含规则就会生效 。 默认的后缀列表是:
1 | .out、 .a、 .ln、 .o、 .c、 .cc、 .C、 .p、 .f、 .F、 .r、 .y、 .l、 .s、 .S、 .mod、 .sym、 |
4.常用隐含规则
4.1编译 C 程序
[n].o 的目标的依赖目标会自动推导为 [n].c ,其生成命令是:
1 | $(CC) –c $(CPPFLAGS) $(CFLAGS) |
4.2编译 C++ 程序
[n].o 的目标的依赖目标会自动推导为 [n].cc 或是 [n].C (建议使用 .cc 作为 C++ 源文件的后缀,而不是 .C ),其生成命令是:
1 | $(CXX) –c $(CPPFLAGS) $(CFLAGS) |
4.3汇编和汇编预处理
[n].o 的目标的依赖目标会自动推导为 [n].s ,默认使用编译器 as ,其生成命令是:
1 | $(AS) $(ASFLAGS) |
[n].s” 的目标的依赖目标会自动推导为 [n].S ,默认使用 C 预编译器 cpp ,其生成命令是:
1 | $(AS) $(ASFLAGS) |
4.4链接 Object 文件
[n] 目标依赖于 .o ,通过运行 C 的编译器来运行链接程序生成(一般是 ld ), 其生成命令是:
1 | $(CC) $(LDFLAGS) [n].o $(LOADLIBES) $(LDLIBS) |
这个规则对于只有一个源文件的工程有效,对多个 Object 文件(由不同的源文件生成)的也有效。例如,如下规则:
1 | main : test1.o test2.o |
并且 main.c 、 test1.c 和 test2.c 都存在时,隐含规则将执行如下命令:
1 | cc -c main.c -o main.o |
如果没有哪个源文件(如上例中的 main.c )和我们的目标名字(如上例中的 main )相关联,那么,最好还是写出自己的生成规则,不然,隐含规则会报错的。
5.预设变量
在隐含规则中的命令中,基本上都是使用了一些预先设置的变量,之前的时候其实我们已经做过笔记了,这里再写一下吧,加深印象。我们可以在 Makefile 中改变这些变量的值,或是在 make 的命令行中传入这些值,或是在环境变量中设置这些值。只要设置了这些特定的变量,那么其就会对隐含规则起作用。
点击查看示例
编译 C 程序的隐含规则的命令是
1 | $(CC) –c $(CFLAGS) $(CPPFLAGS) |
make 默认的编译命令是 cc ,如果把变量 $(CC) 重定义成 gcc ,把 变量 $(CFLAGS) 重定义成 -g ,那么,隐含规则中的命令全部会以下边的形式执行:
1 | gcc –c -g $(CPPFLAGS) |
5.1关于命令的变量
点击查看关于命令的变量
AR | 函数库打包程序。默认命令是“ar” |
AS | 汇编语言编译程序。默认命令是“as” |
CC | C 语言编译程序。默认命令是“cc” |
CXX | C++语言编译程序。默认命令是“g++” |
CO | 从 RCS 文件中扩展文件程序。默认命令是“co” |
CPP | C 程序的预处理器(输出是标准输出设备)。默认命令是“$(CC) –E” |
FC | Fortran 和 Ratfor 的编译器和预处理程序。默认命令是“f77” |
GET | 从 SCCS 文件中扩展文件的程序。默认命令是“get” |
LEX | Lex 方法分析器程序(针对于 C 或 Ratfor)。默认命令是“lex” |
PC | Pascal 语言编译程序。默认命令是“pc” |
YACC | Yacc 文法分析器(针对于 C 程序)。默认命令是“yacc” |
YACCR | Yacc 文法分析器(针对于 Ratfor 程序)。默认命令是“yacc –r” |
MAKEINFO | 转换 Texinfo 源文件(.texi)到 Info 文件程序。默认命令是“makeinfo” |
TEX | 从 TeX 源文件创建 TeX DVI 文件的程序。默认命令是“tex” |
TEXI2DVI | 从 Texinfo 源文件创建军 TeX DVI 文件的程序。默认命令是“texi2dvi” |
WEAVE | 转换 Web 到 TeX 的程序。默认命令是“weave” |
CWEAVE | 转换 C Web 到 TeX 的程序。默认命令是“cweave” |
TANGLE | 转换 Web 到 Pascal 语言的程序。默认命令是“tangle” |
CTANGLE | 转换 C Web 到 C。默认命令是“ctangle” |
RM | 删除文件命令。默认命令是“rm –f” |
5.2关于参数的变量
点击查看关于参数的变量
ARFLAGS | 函数库打包程序 AR 命令的参数。默认值是“rv” |
ASFLAGS | 汇编语言编译器参数。(当明显地调用“.s”或“.S”文件时) |
CFLAGS | C 语言编译器参数 |
CXXFLAGS | C++语言编译器参数 |
COFLAGS | RCS 命令参数 |
CPPFLAGS | C 预处理器参数。( C 和 Fortran 编译器也会用到) |
FFLAGS | Fortran 语言编译器参数 |
GFLAGS | SCCS “get”程序参数 |
LDFLAGS | 链接器参数。(如:“ld”) |
LFLAGS | Lex 文法分析器参数 |
PFLAGS | Pascal 语言编译器参数 |
RFLAGS | Ratfor 程序的 Fortran 编译器参数 |
YFLAGS | Yacc 文法分析器参数 |
二、静态模式
1.静态模式作用
在 Makefile 中,一个规则中可以有多个目标,规则所定义的命令对所有的目标有效,不同的目标可以根据目标文件的名字来自动构造出依赖文件。一个具有多目标的规则相当于多个规则,这样使用多目标可以使 Makefile 文件变得简洁。
2.静态模式语法
1 | <targets ...>: <target-pattern>: <prereq-patterns ...> |
【参数说明】
targets | 定义了一系列的目标文件,可以有通配符。是目标的一个集合。 | |
targets-pattern | 是指明了 targets 的模式,也就是的目标集模式。 | |
prereq-patterns | 是目标的依赖模式,它对 targets-pattern 形成的模式再进行一次依赖目标的定义。 | |
<Tab> | 表示命令的开始(命令前边一定要有Tab) | |
option | @ | 输出的信息中,不要显示此行命令(make执行过程中,默认会显示所执行的命令)。 |
- | 忽略当前此行命令执行时候所遇到的错误。如果不忽略,make在执行命令的时候,如果遇到error,会退出执行的,加上减号后,即便此行命令执行中出错,比如删除一个不存在的文件等,那么也会继续执行make。 | |
command | make 需要执行的命令(任意的 shell 命令)。可以有多条命令,每一条命令占一行 |
<target-parrtern> 定义成 %.o ,意思是我们的 <target> 集合中都是以 .o 结尾的,而如果我们的 <prereq-parrterns> 定义成 %.c , 意思是对 <target-parrtern> 所形成的目标集进行二次定义,其计算方法是,取 <target-parrtern> 模式中的 % (也就是去掉了 [.o] 这个结尾),并为其加上 [.c] 这个结尾,形成的新集合。
所以,我们的“目标模式”或是“依赖模式”中都应该有 % 这个字符,如果文件名中有 % ,那么可以使用反斜杠 \ 进行转义,来标明真实的 % 字符。
3.实例说明
说真的,看完《跟我一起写Makefile》的上关于静态模式的语法后,属实是一脸懵,还是写一个实例,免得下次看到又不理解了。还是使用笔记开头的几个测试文件,我们修改 makefile 内容如下:
1 | OBJ = main.o test1.o test2.o |
然后我们在终端执行 make 命令,会看到如下信息输出:
1 | cc -c main.c -o main.o |
指明了我们的目标从 $(OBJ) 中获取, %.o 表明要所有以 .o 结尾的目标,也就是 main.o 、 test1.o 和 test2.o ,也就是变量 $(OBJ) 集合的模式,而依赖模式 %.c 则取模式 %.o 的 % ,也就是 main 、 test1 和 test2 ,并为其加上 .c 的后缀,于是,我们的依赖目标就是 main.c 、 test1.c 和 test2.c 。而命令中的 $< 和 $@ 则是自动化变量, $< 表示所有的依赖目标集(也就是“ main.c 、 test1.c 和 test2.c ), $@ 表示目标集(也就是 main.o 、 test1.o 和 test2.o ),总结一下就是:
OBJ | 目标的值列表: main.o test1.o test2.o | |
main: $(OBJ) | 最终目标,这个最终目标有依赖文件,${OBJ}表示的是就是所依赖的文件集合,下边的是最终目标的生成命令 | |
$(OBJ): %.o: %.c | $(OBJ) | 指明了目标为 OBJ,即 main.o test1.o test2.o |
%o | 表明是所有以 .o 结尾的目标文件,也就是 main.o 、 test1.o 、和 test2.o ,也就是变量 $OBJ 集合的模式, | |
%c | 依赖模式 %.c 则取模式 %.o 的 % ,也就是 main 、 test1 、和 test2 ,并为其加上 .c 的后缀,于是,我们的依赖就是 main.c 、 test1.c 、和 test2.c | |
$< | 表示所有的依赖目标集(也就是main.c、test1.c、和test2.c) | |
$@ | 表示目标集(也就是main.o、test1.o、和test2.o) |
于是,上面的规则展开后等价于下面的规则:
1 | OBJ = main.o test1.o test2.o |
由此可以看出,使用了静态模式的 Makefile 文件已经简单了很多了,可以想象,如果有上百个 .o 和 .c 文件,这样做,只需要 4 行就可以完成所有 .o 文件的生成了,无疑给我们带来了巨大便利。
三、模式规则
前边学习隐含规则的时候有提到,一行规则可以使用模式规则来定义,什么是模式规则呢?又该如何使用呢?
1.匹配符 %
在 Makefile 中 % 被称为匹配符,也可以称之为模式字符。
make 命令允许对文件名进行类似正则运算的匹配,主要用到的匹配符是 % ,它可以匹配任何非空字符串,主要应用在模式规则中。在依赖目标中同样可以使用 % ,只是依赖目标中的 % 的取值,取决于其目标。
2.模式规则
2.1模式规则格式
首先,还是要来了解以下什么叫模式规则。模式规则的一般格式如下:
1 | .o : %.c |
【参数说明】
%.o | 表示匹配所有的 .o 文件 | |
%.c | 表示匹配所有的 .c 文件 | |
<Tab> | 表示命令的开始(命令前边一定要有Tab) | |
option | @ | 输出的信息中,不要显示此行命令(make执行过程中,默认会显示所执行的命令)。 |
- | 忽略当前此行命令执行时候所遇到的错误。如果不忽略,make在执行命令的时候,如果遇到error,会退出执行的,加上减号后,即便此行命令执行中出错,比如删除一个不存在的文件等,那么也会继续执行make。 | |
command | make 需要执行的命令(任意的 shell 命令)。可以有多条命令,每一条命令占一行 |
【注意】
(1)模式规则中,至少在规则的目标定义中要包含 % ,否则,就是一般的规则。
(2)模式字符 % 的匹配和替换发生在规则中所有变量和函数引用展开之后,变量和函数的展开一般发生在 make 读取 Makefile 时,而模式规则中的 % 的匹配和替换则发生在 make 执行时。
(3)目标中的 % 定义表示对文件名的匹配, % 表示长度任意的非空字符串。例如: %.c 表示以 .c 结尾的文件名(文件名的长度至少为 3 ), 而 s.%.c 则表示以 s. 开头, .c 结尾的文件名(文件名的长度至少为 5 )。
(4)如果 % 定义在目标中,那么,目标中的 % 的值决定了依赖目标中的 % 的值,也就是说,目标中的模式的 % 决定了依赖目标中 % 的样子。例如, %.o 匹配到了文件 main.o ,那么, %.c 就代表着 main.c 。
- 一个小实例
1 | %.o : %.c |
上边的规则将把所有的 .c 文件都编译成 .o 文件.
2.2模式规则要求
模式规则与普通规则类似,但是模式规则有以下要求:
- (1)目标名
对于目标名来说,目标名中需要包含一个模式字符 % ,包含有模式字符 % 的目标被用来匹配一个文件名。在目标文件名中 % 匹配的部分称为茎,比如,目标名为 %.o ,匹配到了一个 main.o 文件,那么 % 就代表 main ,也就是茎。
若目标模式中包含斜杠(也就是目录部分),在进行目标文件匹配时,文件名中包含的目录字符串在匹配之前被移除,只进行基本文件名的匹配;匹配成功后,再将目录加入到匹配之后的字符串之前形成茎。
点击查看实例说明
目标模式为 m%n ,文件 src/main 和这个目标模式相匹配,那么茎就是 src/ai 。
模式规则中依赖文件的产生是:首先使用茎的非目录部分( ai )替代依赖文件中的模式字符 % ,之后再将目录部分( src/ )加入到形成的依赖文件名之前构成依赖文件的全路径名。这里如果模式规则的依赖模式为 t%t ,则那么目标 src/main 对应的依赖文件就为 src/tait 。
- (2)依赖文件
依赖文件中同样可以使用 % ,依赖文件中模式字符 % 的取值情况由目标中的 % 来决定。例如,对于模式规则 %.o : %.c ,它表示的含义是:所有的 .o 文件依赖于对应的 .c 文件。例如,如果要生成的目标 %.o 是 a.o b.o 那么 %.c 就是 a.c b.c 。
模式规则中的依赖文件也可以不包含模式字符 % 。当依赖文件名中不包含模式字符 % 时,其含义是所有符合目标模式的目标文件都依赖于一个指定的文件(例如: %.o : test.h ,表示所有的 .o 文件都依赖于头文件 test.h )。
- (3)多目标
一个模式规则可以存在多个目标。多目标的模式规则和普通多目标规则有些不同:
普通多目标规则的处理是将每一个目标作为一个独立的规则来处理,所以多个目 标就就对应多个独立的规则(这些规则各自有自己的命令行,各个规则的命令行可能相同)。
对于多目标模式规则来说,所有规则的目标共同拥有依赖文件和规则的命令行,当文件符合多个目标模式中的任何一个时,规则定义的命令就有可能将会执行;因为多个目标共同拥有规则的命令行,因此一次命令执行之后,规则不会再去检查是否需要重建符合其它模式的目标。
点击查看多目标的相关实例
点击查看相关文件内容
1 |
|
1 |
|
Makefile 文件内容如下:
1 | Objects = main.o test.o |
然后那我们执行 make main.o main.x 时,会看到只有一个文件 main.o 被创建了,同时 make 会有以下提示,
1 | cc -Wall -O2 main.c -o main.o |
但是实际上, main.x 文件并未被创建。这个例子表明了多目标的模式规则在 make 处理时是作为一个整体来处理的,这是多目标模式规则和多目标的普通规则的不同之处。
【注意】
(1)模式规则在 Makefile 中的顺序需要注意,当一个目标文件符合多个模式规则的目标时, make 将会按照第一个找到的作为重建它的规则。
(2)在 Makefile 中指定的模式规则会覆盖隐含的模式规则。就是说在 Makefile 中明确指定的会替代隐含的模式规则。
(3)依赖文件存在或者被提及的规则,优先于那些需要使用隐含规则来创建其依赖文件的规则。
3.实例说明
其实这个实例与静态模式的实例是一样的,静态模式的语法是建立在模式规则的基础上的,依靠模式规则完成静态模式语法。还是使用笔记开头的几个测试文件,我们修改 makefile 内容如下:
1 | OBJ = main.o test1.o test2.o |
然后我们在终端执行 make 命令,会看到如下信息输出:
1 | cc -c main.c -o main.o |
指明了我们的目标从 $(OBJ) 中获取, %.o 表明要所有以 .o 结尾的目标,也就是 main.o 、 test1.o 和 test2.o ,也就是变量 $(OBJ) 集合的模式,而依赖模式 %.c 则取模式 %.o 的 % ,也就是 main 、 test1 和 test2 ,并为其加上 .c 的后缀,于是,我们的依赖目标就是 main.c 、 test1.c 和 test2.c 。而命令中的 $< 和 $@ 则是自动化变量, $< 表示所有的依赖目标集(也就是“ main.c 、 test1.c 和 test2.c ), $@ 表示目标集(也就是 main.o 、 test1.o 和 test2.o ),总结一下就是:
OBJ | 目标的值列表: main.o test1.o test2.o | |
main: $(OBJ) | 最终目标,这个最终目标有依赖文件,${OBJ}表示的是就是所依赖的文件集合,下边的是最终目标的生成命令 | |
$(OBJ): %.o: %.c | $(OBJ) | 指明了目标为 OBJ,即 main.o test1.o test2.o |
%o | 表明是所有以 .o 结尾的目标文件,也就是 main.o 、 test1.o 、和 test2.o ,也就是变量 $OBJ 集合的模式, | |
%c | 依赖模式 %.c 则取模式 %.o 的 % ,也就是 main 、 test1 、和 test2 ,并为其加上 .c 的后缀,于是,我们的依赖就是 main.c 、 test1.c 、和 test2.c | |
$< | 表示所有的依赖目标集(也就是main.c、test1.c、和test2.c) | |
$@ | 表示目标集(也就是main.o、test1.o、和test2.o) |
于是,上面的规则展开后等价于下面的规则:
1 | OBJ = main.o test1.o test2.o |
四、 Makefile 通配符
Makefile 可以使用 Shell 命令,所以 Shell 中的通配符在 Makefile 中也同样适用。
1.常用通配符
通配符 | 使用说明 |
* | 匹配0个或者是任意个字符 |
? | 匹配任意一个字符 |
[] | 我们可以指定匹配的字符放在 "[]" 中 |
【注意】
(1)通配符可以用在命令中,例如,
1 |
|
(2)通配符可以用在规则中,例如,
1 | main:*.c |
但是,不可以通过引用变量的方式来使用。例如,
1 | # 以下是不被允许的 |
如果我们就是相要通过引用变量的话,我们要使用一个函数 wildcard ,这个后边学习到函数的时候会详细说明。
2. % 与 *
上边学习模式规则的时候,我们接触到了 % ,它可以匹配任意非空字符串, * 也可以用于规则中来匹配字符串,那么它们是完全一样的嘛?当然不是一样的啦。其实我们可以尝试一下以下两种规则有什么不同,我们还是使用笔记开头的测试文件:
Makefile 文件内容如下:
1 | OBJ = main.o test1.o test2.o |
运行 make 命令后,会正常生成所有文件。终端输出的信息如下:
1 | gcc -c main.c -o main.o |
接下来我们分析一下这个文件中的 %.o: %.c , %.o 匹配所有的 .o 目标文件 main.o 、 test1.o 和 test2.o ,然后得到相应的茎,也就是 % 所匹配的内容 main 、 test1 和 test2 ,然后后边的 %.c 就分别代表 main.c 、 test1.c 和 test2.c 。
Makefile 文件内容如下:
1 | OBJ = main.o test1.o test2.o |
运行 make 命令后,会正常生成所有文件。终端输出的信息如下:
1 | cc -c -o main.o main.c |
会发现,这个输出信息好奇怪啊,为什么是 cc 开头,我的命令不是 gcc 嘛,据推测,它默认还是使用了隐含规则来生成文件。
不过我们依然可以分析一下 * 的作用, *.c 就表示只要是 .c 文件,全都是我要找的,找到后就进行编译。
总之, % 与 * 都是匹配字符串,但是,他们的工作方式却不同,要注意一下。
五、隐含规则搜索算法
这段说真的,我没看懂,但是可能对之后理解或者编写 Makefile 有一定的帮助,笔记记在这里慢慢理解把,哈哈。
比如我们有一个目标叫 T 。下面是搜索目标 T 的规则的算法。请注意,在下面,我们没有提到后缀规则,原因是,所有的后缀规则在 Makefile 被载入内存时,会被转换成模式规则。如果目标是 archive(member) 的函数库文件模式,那么这个算法会被运行两次,第一次是找目标 T ,如果没有找到的话,那么进入第二次,第二次会把 member 当作 T (也就是目标) 来搜索。
- 1、把 T 的目录部分分离出来。叫 D ,而剩余部分叫 N 。
例如:若 T 是 src/foo.o ,那么, D 就是 src/ , N 就是 foo.o 。
2、创建所有匹配于 T 或是 N 的模式规则列表。
3、如果在模式规则列表中有匹配所有文件的模式,如 % ,那么从列表中移除其它的模式。
4、移除列表中没有命令的规则。
5、对于第一个在列表中的模式规则:
(1)推导其”茎” S , S 应该是 T 或是 N 匹配于模式中 % 非空的部分。
(2)计算依赖文件。把依赖文件中的 % 都替换成”茎” S 。如果目标模式中没有包含斜框字符,而把 D 加在第一个依赖文件的开头。
(3)测试是否所有的依赖文件都存在或是理当存在。(如果有一个文件被定义成另外一个规则的目标文件,或者是一个显式规则的依赖文件, 那么这个文件就叫”理当存在”)。
(4)如果所有的依赖文件存在或是理当存在,或是就没有依赖文件。那么这条规则将被采用,退出该算法。
- 6、如果经过第 5 步,没有模式规则被找到,那么就做更进一步的搜索。对于存在于列表中的第一个模式规则
(1)如果规则是终止规则,那就忽略它,继续下一条模式规则。
(2)计算依赖文件。 (同第 5 步)
(3)测试所有的依赖文件是否存在或是理当存在。
(4)对于不存在的依赖文件,递归调用这个算法查找他是否可以被隐含规则找到 。
(5)如果所有的依赖文件存在或是理当存在,或是就根本没有依赖文件。那么这条规则被采用,退出该算法。
- 7、如果没有隐含规则可以使用,查看 .DEFAULT 规则,如果有,采用,把 .DEFAULT 的命令给 T 使用。一旦规则被找到,就会执行其相当的命令,而此时,我们的自动化变量的值才会生成。