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

目录

一、使用隐含规则

二、隐含规则一览

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”也是同样的规则。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/629018.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

如何编译openssl的早期版本的共享库,如openssl 1.0

背景介绍 最近在为客户排查问题的时候&#xff0c;发现客户提供的日志是加密的&#xff0c;解密工具依赖到了openssl 1.0的共享库。可是手头没有这么老版本的openssl共享库。因此只好手动编译一个出来。 编译步骤 因为openssl 1.0是比较老的版本&#xff0c;很多系统上的库已…

常用Java代码-Java中的注解处理器(Annotation Processing)

注解处理器&#xff08;Annotation Processing&#xff09;是Java编译时的一种机制&#xff0c;它允许开发者在源代码上添加注解&#xff0c;并通过注解处理器生成源代码、报告编译器错误或警告、或者进行其他编译时操作。 在Java中&#xff0c;注解处理器通常使用Java的反射和…

新能源汽车智慧充电桩解决方案:智慧化综合管理与数字化高效运营

一、方案概述 TSINGSEE青犀&触角云新能源汽车智慧充电桩解决方案基于管理运营平台&#xff0c;覆盖业务与应用、数据传输与梳理、多端开发、搭建等模块&#xff0c;融合AI、5G、Wi-Fi 、移动支付等技术&#xff0c;实现充电基础设施由数字化向智能化演进&#xff0c;通过构…

【算法题】57. 插入区间

题目 给你一个 无重叠的 &#xff0c;按照区间起始端点排序的区间列表。 在列表中插入一个新的区间&#xff0c;你需要确保列表中的区间仍然有序且不重叠&#xff08;如果有必要的话&#xff0c;可以合并区间&#xff09;。 示例 1&#xff1a; 输入&#xff1a;intervals …

翻译: Pyenv管理Python版本从入门到精通一

你是否经常在管理系统上多个Python版本时遇到困难&#xff1f;这可能是一个艰巨的任务&#xff0c;尤其是在处理需要不同Python版本的不同项目时。 但别担心&#xff0c;有一个解决方案&#xff1a;pyenv。就像一个熟练的杂技演员&#xff0c;pyenv可以轻松处理多个Python版本…

Vue插槽(slot)的使用

Vue插槽(slot)是一种强大的功能&#xff0c;它允许您在组件模板中插入自定义内容。插槽可以让你更灵活地构建组件&#xff0c;以满足不同的使用场景。 使用说明&#xff1a; 定义插槽&#xff1a;在组件模板中&#xff0c;使用<slot>标签来定义插槽。使用插槽&#xff…

连接超时的问题

连接超时的问题 通用第三方工具连接超时 connect timeout 方案一&#xff1a; /etc/ssh/sshd_config node1上操作&#xff0c;图是错的 方案二&#xff1a; windows上Hosts文件域名解析有问题 比如&#xff1a; 192.168.xx.100 node1 192.168.xx.161 node1 两个都解析成node…

绝地求生:【PC】未授权程序使用行为的相关公告

各位玩家大家好&#xff0c; 最近闲游盒通过PUBG玩家社区收到了关于未授权程序的举报&#xff0c;举报称有人在游戏内使用了能测量玩家间的距离并辅助迫击炮射击的未授权辅助程序。为此&#xff0c;我们想就该事项向大家进行如下公告&#xff1a; 使用此类未授权程序的行为违反…

23/76-LeNet

LeNet 早期成功的神经网络。 先使用卷积层来学习图片空间信息。 然后使用全连接层转换到类别空间。 #In[]LeNet,上世纪80年代的产物,最初为了手写识别设计from d2l import torch as d2l import torch from torch import nn from torch.nn.modules.loss import CrossEntropyLos…

无法加载操作系统,原因是关键系统驱动程序丢失或包含错误

bcdboot c:\windows /l zh-cn 用这个命令解决了,没有进入时候蓝屏了,不知道为什么 问题 无法加载操作系统,原因是关键系统驱动程序丢失或包含错误上午因为有点事就没有像往常一样打开电脑,下午回到家休息了一会本来准备打开电脑开始我愉快地下午生活,没想到一个自动恢复给…

工业平板定制方案_基于联发科、紫光展锐平台的工业平板电脑方案

工业平板主板采用联发科MT6762平台方案&#xff0c;搭载Android 11.0操作系统&#xff0c; 主频最高2.0GHz&#xff0c;效能有大幅提升;采用12nm先进工艺&#xff0c;具有低功耗高性能的特点。 该工业平板主板搭载了IMG GE8320图形处理器&#xff0c;最高主频为680MHz, 支持108…

Java设计模式之访问者模式详解

Java设计模式之访问者模式详解 大家好&#xff0c;我是免费搭建查券返利机器人赚佣金就用微赚淘客系统3.0的小编&#xff0c;也是冬天不穿秋裤&#xff0c;天冷也要风度的程序猿&#xff01;今天&#xff0c;让我们一同踏上Java设计模式之旅&#xff0c;探索访问者模式&#x…

Flume 之自定义Sink

1、简介 前文我们介绍了 Flume 如何自定义 Source&#xff0c; 并进行案例演示&#xff0c;本文将接着前文&#xff0c;自定义Sink&#xff0c;在这篇文章中&#xff0c;将使用自定义 Source 和 自定义的 Sink 实现数据传输&#xff0c;让大家快速掌握Flume这门技术。 2、自定…

JVM与HotSpot

JVM和HotSpot 1、概念 JVM是虚拟机的规范&#xff0c;HotSpot是jvm的具体实现 HotSpot包括一个解释器和两个编译器&#xff08;client 和 server&#xff0c;二选一的&#xff09;&#xff0c;解释与编译混合执行模式&#xff0c;默认启动解释执行。 编译器&#xff1a;java源…

121_买卖股票的最佳时机

描述 给定一个数组 prices &#xff0c;它的第 i 个元素 prices[i] 表示一支给定股票第 i 天的价格。 你只能选择某一天买入这只股票&#xff0c;并选择在未来的某一个不同的日子卖出该股票。设计一个算法来计算你所能获取的最大利润。 返回你可以从这笔交易中获取的最大利润。…

Python - 深夜数据结构与算法之 Sort

目录 一.引言 二.排序简介 1.排序类型 2.时间复杂度 3.初级排序 4.高级排序 A.快速排序 B.归并排序 C.堆排序 5.特殊排序 三.经典算法实战 1.Quick-Sort 2.Merge-Sort 3.Heap-Sort 4.Relative-Sort-Array [1122] 5.Valid-anagram [242] 6.Merge-Intervals […

Java NIO (二)NIO Buffer类的重要方法(备份)

1 allocate()方法 在使用Buffer实例前&#xff0c;我们需要先获取Buffer子类的实例对象&#xff0c;并且分配内存空间。需要获取一个Buffer实例对象时&#xff0c;并不是使用子类的构造器来创建&#xff0c;而是调用子类的allocate()方法。 public class AllocateTest {static…

如何快速看懂一篇英文AI论文?

已经2024年了&#xff0c;该出现一个写论文解读AI Agent了。 大家肯定也在经常刷论文吧。 但真正尝试过用GPT去刷论文、写论文解读的小伙伴&#xff0c;一定深有体验——费劲。其他agents也没有能搞定的&#xff0c;今天我发现了一个超级厉害的写论文解读的agent &#xff0c…

某银行主机安全运营体系建设实践

随着商业银行业务的发展&#xff0c;主机规模持续增长&#xff0c;给安全团队运营工作带来极大挑战&#xff0c;传统的运营手段已经无法适应业务规模的快速发展&#xff0c;主要体现在主机资产数量多、类型复杂&#xff0c;安全团队难以对全量资产进行及时有效的梳理、管理&…

JS中数组的相关方法介绍

push() 将一个或多个元素添加到数组的末尾&#xff0c;并返回新的长度。 let arr [1, 2, 3]; arr.push(4); // arr 现在是 [1, 2, 3, 4] pop() 删除并返回数组的最后一个元素 let arr [1, 2, 3, 4]; let last arr.pop(); // last 现在是 4&#xff0c;arr 现在是 [1, …