【问题标题】:Why does GCC compile itself 3 times?为什么 GCC 会自己编译 3 次?
【发布时间】:2020-03-06 15:54:05
【问题描述】:

我已经从源代码编译了 GCC,但我似乎无法完全理解 gcc 编译自身 三次 次的实用性。

这有什么好处?

这个answer 说:

  • 使用现有 C 编译器构建新版本的 GCC
  • 用刚刚构建的 GCC 重新构建新版本
  • (可选)重复第 2 步以进行验证。

现在我的问题是,一旦第一步完成并构建编译器为什么要浪费时间重新构建它?

只是为了验证吗?如果是这样,那似乎很浪费。

事情变得更复杂了over here

这个构建比以前的包更复杂,因为 您正在将更多信息发送到配置脚本和 make 目标不是标准的。

我的意思是整个编译器都是用 C 语言编写的,所以为什么不一次完成所有事情呢?

三相自举有什么用?

提前致谢。

【问题讨论】:

  • “为什么要浪费时间重建它?”这句话中“它”的含义。第 1 阶段与第 2 阶段和第 3 阶段不同。请参阅下面的新的和更深入的答案。最后两个阶段绝不是浪费时间。

标签: gcc architecture compiler-construction bootstrapping


【解决方案1】:
  • 第 2 阶段和第 3 阶段是对编译器本身的一个很好的测试:如果它可以自己编译(通常还有一些库,如 libgcclibstdc++-v3),那么它可以咀嚼非平凡的项目。

  • 在第 2 阶段和第 3 阶段,您可以生成不同的编译器选项,例如不优化 (-O0) 或优化 (-O2)。由于程序的输出/副作用不应取决于所使用的优化级别,任何一个版本的编译器都必须生成相同的二进制文件,即使它们的二进制文件非常不同。这是编译器的另一个(运行时测试)。

如果您出于某种原因更喜欢非引导程序,请配置 --disable-bootstrap

【讨论】:

  • 就是这样,测试?我可以禁用整个过程并在 1 次通过?
  • 通常新版本的 GCC 会产生更好(即更快)的代码。所以第二次构建的想法是产生一个运行速度更快的编译器,利用它本身实现的更好的优化。如果您确信您现有的编译器已经尽可能地编译,那么您为什么要尝试升级?相反,如果您正在升级,为什么不想利用升级?正如引用的答案所说,(可选)第三次编译是为了验证一切是否按预期工作。
  • @rici 通常从源代码构建编译器的主要原因是为了调试、开发或利用可能需要自定义补丁的高度实验性语言功能。让编译器本身稍微快一点与这些无关。
【解决方案2】:

从信息论的角度考虑这个问题,编译器的三阶段编译的第一阶段不会产生编译器。它产生了一个需要实验验证的假设。一个好的编译器分发包的标志是,它将生成开箱即用且无需系统管理员或编译器开发人员进一步工作的分发版本的工作编译器,并具有该版本编译器的所需功能.

实现这一目标并不简单。考虑目标环境中的变量。

  • 目标操作系统品牌
  • 操作系统版本
  • 操作系统设置
  • Shell 环境变量
  • 可包含的标头
  • 可用于链接的库
  • 传递给构建过程的设置
  • 目标处理单元的架构
  • 处理单元数
  • 总线架构
  • 执行模型的其他特征
  • 编译器开发者可能犯的错误
  • 构建编译器的人可能会犯的错误

在 GNU 编译器工具集和许多 tarball 发行版中,“configure”程序试图生成一个构建配置,以尽可能多地适应这些配置。 configure 没有错误或警告的完成并不能保证编译器将正常工作。此外,对于这个问题,更重要的是,构建的完成也不能保证。

新构建的编译器可能适用于 HelloWorld.c,但不适用于名为“智能星际控制和采集系统”的多项目、多存储库软件集合中的一千个源文件集合。

第二阶段和第三阶段是检查至少一些编译器功能的合理尝试,因为编译器源代码本身很方便,并且对刚刚构建的假设工作编译器有相当多的要求。

重要的是要了解第一阶段的结果和第二阶段的结果不会匹配。它们的可执行文件和其他构建工件是来自两个不同编译器的结果。第一阶段的结果是使用在“PATH”变量中列出的目录之一中找到的任何构建系统编译的,以编译 C 和 C++ 源代码。第二阶段的结果是使用假设工作的新编译器编译的。有趣的概率考虑是这样的:

如果使用第一阶段的结果再次编译编译器的结果与使用第二阶段的结果第三次编译编译器的结果完全相同,那么至少对于编译器源代码所需的功能来说,两者都可能是正确的。

最后一句话可能需要重读十几遍。它其实是一个简单的想法,但是动词compile和名词编译器的冗余可以打结,需要几分钟才能解开并能够重新打结。源、目标和执行的动作具有相同的语言根,不止一次,而是三次。

截至 2020 年 5 月 25 日,编译器的构建说明说明了相反的情况,这更容易理解,但只是轶事,没有深入了解三个阶段很重要的原因。

如果 stage2 和 stage3 比较失败,这通常表明 stage2 编译器编译的 GCC 不正确,因此是一个潜在的严重错误,您应该调查并报告。

如果我们从可靠性评估、测试优先、极限编程、6-Sigma 或全面质量管理的角度考虑 C/C++ 开发,C/C++ 开发环境中的哪个组件必须比编译器更可靠?不多。甚至自早期以来 GNU 编译器包一直在使用的编译器的三阶段引导也是一个合理但并非详尽的测试。这就是为什么包中有额外的测试。

从持续集成的角度来看,在编译和部署新编译器之前和之后,应该对即将使用新编译器的人开发的整个软件进行测试。这是确保新编译器不会破坏构建的最便捷方式。

在三个可靠性检查点之间,大多数人都感到满意。

  1. 确保编译器始终如一地编译自己
  2. 编译器开发人员在其发行版中添加的其他测试
  3. 开发者或系统管理员源代码域未被升级破坏

在数学方面,实际上不可能用地球上可用的硅和碳对编译器进行详尽的测试。 C++ 语言抽象中的递归界限(除其他外)是无限的,因此测试源代码的每个排列所需的芯片或时间位置实际上并不存在。在碳方面,没有任何人可以腾出必要的时间来充分研究源代码,以保证编译器源代码不会以某种方式施加一些有限的限制。”

三个级别的检查,其中只有一个是三阶段引导过程,对我们大多数人来说可能就足够了。

三阶段编译的另一个好处是新编译器使用新编译器进行编译,新编译器在速度或资源消耗方面可能更好,可能两者兼而有之。

【讨论】:

    猜你喜欢
    • 2013-10-19
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2017-05-31
    • 1970-01-01
    • 2019-02-19
    • 2013-08-08
    • 2011-03-31
    相关资源
    最近更新 更多