为什么 GCC 会自己编译 3 次?

ng.*_*bie 7 architecture compiler-construction gcc bootstrapping

我编了从源头GCC,但我似乎无法完全理解的效用gcc编制本身3倍。

这有什么好处?

这个答案说:

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

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

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

事情在这里变得更复杂,

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

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

三相自举有什么用?

提前致谢。

ema*_*uts 7

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

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

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

  • 通常新版本的 GCC 会生成更好(即更快)的代码。因此,第二个构建的想法是产生一个运行速度更快的编译器,利用其本身实现的更好的优化。如果您确信现有的编译器已经可以很好地编译,为什么要尝试升级?相反,如果您正在升级,为什么您不想利用升级呢?正如引用的答案所说,(可选)第三次编译是为了验证一切是否按预期工作。 (3认同)
  • @rici 人们通常从源代码构建编译器的主要原因是为了调试、开发或使用可能需要自定义补丁的高度实验性语言功能。使编译器本身稍微快一点与这些无关。 (2认同)

Dou*_*eco 5

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

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

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

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

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

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

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

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

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

截至 2020 年 5 月 25 日,编译器的构建指令说明了相反的情况,这更容易理解,但仅仅是轶事,没有抓住三个阶段如此重要的关键原因。

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

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

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

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

  1. 确保编译器一致地编译自身
  2. 编译器开发人员在其发行版中放入的其他测试
  3. 开发人员或系统管理员源代码域不会因升级而破坏

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

这三个级别的检查(其中只有一个是三阶段引导过程)可能足以满足我们大多数人的需要。

三阶段编译的另一个好处是,新编译器是用新编译器编译的,新编译器在速度或资源消耗方面可能更好,甚至可能两者都更好。