第十一部分 隐含规则 (一)

发布时间:2024年01月17日

目录

一、使用隐含规则

二、隐含规则一览

1、编译 C 程序的隐含规则

2、编译 C++程序的隐含规则

3、编译 Pascal 程序的隐含规则

4、编译 Fortran/Ratfor 程序的隐含规则

5、预处理 Fortran/Ratfor 程序的隐含规则

6、编译 Modula-2 程序的隐含规则

7、汇编和汇编预处理的隐含规则

8、链接 Object 文件的隐含规则

9、Yacc C 程序时的隐含规则

10、Lex C 程序时的隐含规则

11、Lex Ratfor 程序时的隐含规则

12、从 C 程序、Yacc 文件或 Lex 文件创建 Lint 库的隐含规则


????????在我们使用 Makefile 时,有一些我们会经常使用,而且使用频率非常高的东西,比如, 我们编译 C/C++的源程序为中间目标文件(Unix 下是[.o]文件,Windows 下是[.obj]文件)。 本章讲述的就是一些在 Makefile 中的“隐含的”,早先约定了的,不需要我们再写出来的 规则。

???????? “隐含规则”也就是一种惯例,make 会按照这种“惯例”心照不喧地来运行,那怕我 们的 Makefile 中没有书写这样的规则。例如,把[.c]文件编译成[.o]文件这一规则,你根 本就不用写出来,make 会自动推导出这种规则,并生成我们需要的[.o]文件。

???????? “隐含规则”会使用一些我们系统变量,我们可以改变这些系统变量的值来定制隐含规 则的运行时的参数。如系统变量“CFLAGS”可以控制编译时的编译器参数。

????????我们还可以通过“模式规则”的方式写下自己的隐含规则。用“后缀规则”来定义隐含 规则会有许多的限制。使用“模式规则”会更回得智能和清楚,但“后缀规则”可以用来保 证我们 Makefile 的兼容性。

????????我们了解了“隐含规则”,可以让其为我们更好的服务,也会让我们知道一些“约定俗 成”了的东西,而不至于使得我们在运行 Makefile 时出现一些我们觉得莫名其妙的东西。 当然,任何事物都是矛盾的,水能载舟,亦可覆舟,所以,有时候“隐含规则”也会给我们 造成不小的麻烦。只有了解了它,我们才能更好地使用它。

一、使用隐含规则

????????如果要使用隐含规则生成你需要的目标,你所需要做的就是不要写出这个目标的规则。 那么,make 会试图去自动推导产生这个目标的规则和命令,如果 make 可以自动推导生成这 个目标的规则和命令,那么这个行为就是隐含规则的自动推导。当然,隐含规则是 make 事 先约定好的一些东西。例如,我们有下面的一个 Makefile:

foo : foo.o bar.o

cc –o foo foo.o bar.o $(CFLAGS) $(LDFLAGS)

???????? 我们可以注意到,这个 Makefile 中并没有写下如何生成 foo.o 和 bar.o 这两目标的规 则和命令。因为 make 的“隐含规则”功能会自动为我们自动去推导这两个目标的依赖目标 和生成命令。

????????make 会在自己的“隐含规则”库中寻找可以用的规则,如果找到,那么就会使用。如 果找不到,那么就会报错。在上面的那个例子中,make 调用的隐含规则是,把[.o]的目标的依赖文件置成[.c],并使用 C 的编译命令“cc –c $(CFLAGS) [.c]”来生成[.o]的目标。 也就是说,我们完全没有必要写下下面的两条规则:

foo.o : foo.c

cc –c foo.c $(CFLAGS)

bar.o : bar.c

cc –c bar.c $(CFLAGS)

???????? 因为,这已经是“约定”好了的事了,make 和我们约定好了用 C 编译器“cc”生成[.o] 文件的规则,这就是隐含规则。

????????当然,如果我们为[.o]文件书写了自己的规则,那么 make 就不会自动推导并调用隐含 规则,它会按照我们写好的规则忠实地执行。

????????还有,在 make 的“隐含规则库”中,每一条隐含规则都在库中有其顺序,越靠前的则 是越被经常使用的,所以,这会导致我们有些时候即使我们显示地指定了目标依赖,make 也不会管。如下面这条规则(没有命令):

foo.o : foo.p

????????依赖文件“foo.p”(Pascal 程序的源文件)有可能变得没有意义。如果目录下存在了 “foo.c”文件,那么我们的隐含规则一样会生效,并会通过“foo.c”调用 C 的编译器生成 foo.o 文件。因为,在隐含规则中,Pascal 的规则出现在 C 的规则之后,所以,make 找到 可以生成foo.o的C的规则就不再寻找下一条规则了。如果你确实不希望任何隐含规则推导, 那么,你就不要只写出“依赖规则”,而不写命令。

二、隐含规则一览

????????这里我们将讲述所有预先设置(也就是 make 内建)的隐含规则,如果我们不明确地写 下规则,那么,make 就会在这些规则中寻找所需要规则和命令。当然,我们也可以使用 make 的参数“-r”或“--no-builtin-rules”选项来取消所有的预设置的隐含规则。

????????当然,即使是我们指定了“-r”参数,某些隐含规则还是会生效,因为有许多的隐含规 则都是使用了“后缀规则”来定义的,所以,只要隐含规则中有“后缀列表”(也就一系统 定义在 目标 .SUFFIXES 的依赖 目标 ),那么 隐 含规则 就会 生效。 默认 的后缀 列 表 是:.out,.a, .ln, .o, .c, .cc, .C, .p, .f, .F, .r, .y, .l, .s, .S, .mod, .sym, .def, .h, .info, .dvi, .tex, .texinfo, .texi, .txinfo, .w, .ch .web, .sh, .elc, .el。 具体的细节,我们会在后面讲述。

还是先来看一看常用的隐含规则吧。

1、编译 C 程序的隐含规则

“<n>.o”的目标的依赖目标会自动推导为“<n>.c”,并且其生成命令是“$(CC) –c $(CPPFLAGS) $(CFLAGS)”

2、编译 C++程序的隐含规则

“<n>.o”的目标的依赖目标会自动推导为“<n>.cc”或是“<n>.C”,并且其生成命令 是“$(CXX) –c $(CPPFLAGS) $(CFLAGS)”。(建议使用“.cc”作为 C++源文件的后缀,而 不是“.C”)

3、编译 Pascal 程序的隐含规则

“<n>.o”的目标的依赖目标会自动推导为“<n>.p”,并且其生成命令是“$(PC) –c $ (PFLAGS)”。

4、编译 Fortran/Ratfor 程序的隐含规则

????????“<n>.o”的目标的依赖目标会自动推导为“<n>.r”或“<n>.F”或“<n>.f”,并且其 生成命令是:

“.f” “$(FC) –c $(FFLAGS)”

“.F” “$(FC) –c $(FFLAGS) $(CPPFLAGS)”

“.f” “$(FC) –c $(FFLAGS) $(RFLAGS)”

5、预处理 Fortran/Ratfor 程序的隐含规则

???????? “<n>.f”的目标的依赖目标会自动推导为“<n>.r”或“<n>.F”。这个规则只是转换 Ratfor 或有预处理的 Fortran 程序到一个标准的 Fortran 程序。其使用的命令是:

“.F” “$(FC) –F $(CPPFLAGS) $(FFLAGS)”

“.r” “$(FC) –F $(FFLAGS) $(RFLAGS)”

6、编译 Modula-2 程序的隐含规则

????????“<n>.sym”的目标的依赖目标会自动推导为“<n>.def”,并且其生成命令是: “$(M2C)$(M2FLAGS) $(DEFFLAGS)” 。 “” 的 目 标 的 依 赖 目 标 会 自 动 推 导 为“<n>.mod”, 并且其生成命令是:“$(M2C) $(M2FLAGS) $(MODFLAGS)”。

7、汇编和汇编预处理的隐含规则

????????“<n>.o” 的目标的依赖目标会自动推导为“<n>.s”,默认使用编译品“as”,并且 其生成命令是:“$(AS) $(ASFLAGS)”。“<n>.s” 的目标的依赖目标会自动推导为 “<n>.S”,默认使用 C 预编译器“cpp”,并且其生成命令是:“$(AS) $(ASFLAGS)”。

8、链接 Object 文件的隐含规则

“”<n>目标依赖于“<n>.o”,通过运行 C 的编译器来运行链接程序生成(一般是 “ld”),其生成命令是:“$(CC) $(LDFLAGS) .o $(LOADLIBES) $(LDLIBS)”。这个规 则对于只有一个源文件的工程有效,同时也对多个 Object 文件(由不同的源文件生成)的 也有效。例如如下规则:

x : y.o z.o

并且“x.c”、“y.c”和“z.c”都存在时,隐含规则将执行如下命令:

cc -c x.c -o x.o

cc -c y.c -o y.o

cc -c z.c -o z.o

cc x.o y.o z.o -o x

rm -f x.o

rm -f y.o

rm -f z.o

????????如果没有一个源文件(如上例中的 x.c)和你的目标名字(如上例中的 x)相关联,那 么,你最好写出自己的生成规则,不然,隐含规则会报错的。

9、Yacc C 程序时的隐含规则

“<n>.c”的依赖文件被自动推导为“n.y”(Yacc 生成的文件),其生成命令是: “$(YACC) $(YFALGS)”。(“Yacc”是一个语法分析器,关于其细节请查看相关资料)

10、Lex C 程序时的隐含规则

“<n>.c”的依赖文件被自动推导为“n.l”(Lex 生成的文件),其生成命令是:“$(LEX) $(LFALGS)”。(关于“Lex”的细节请查看相关资料)

11、Lex Ratfor 程序时的隐含规则

“.r”的依赖文件被自动推导为“n.l”(Lex 生成的文件),其生成命令是:“$(LEX) $(LFALGS)”。

12、从 C 程序、Yacc 文件或 Lex 文件创建 Lint 库的隐含规则

“<n>.ln” (lint 生成的文件)的依赖文件被自动推导为“n.c”,其生成命令是:“$(LINT) $(LINTFALGS) $(CPPFLAGS) -i”。对于“<n>.y”和“<n>.l”也是同样的规则。

文章来源:https://blog.csdn.net/qq_42700289/article/details/135589244
本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。