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

Why does GCC compile itself 3 times?

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

这有什么好处?

这个answer说:

  • Build new version of GCC with existing C compiler
  • re-build new version of GCC with the one you just built
  • (optional) repeat step 2 for verification purposes.

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

是否只是为了验证?那样的话,就显得很浪费了。

事情变得更加复杂over here,

The build for this is more complex than for prior packages, because you’re sending more information into the configure script and the make targets aren’t standard.

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

3相有什么用bootstrap?

提前致谢。

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

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

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

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

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

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

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

新构建的编译器可能适用于 HelloWorld.c 但不适用于 multi-project、multi-repository collection 中的一千个源文件中的 collection软件调用,"Intelligent Interplanetary Control and Acquisition System."

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

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

If the result of using stage one's result to compile the compiler again equals exactly the result of using stage two's result to compile the compiler a third time, then both are likely correct for at least the features that the compiler's source code requires.

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

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

If the comparison of stage2 and stage3 fails, this normally indicates that the stage2 compiler has compiled GCC incorrectly, and is therefore a potentially serious bug which you should investigate and report.

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

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

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

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

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

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

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