11

我正在尝试从零开始理解 Linux 的概念,并想知道为什么要进行多次构建binutilsgcc

为什么我们分别需要 pass1 和 pass2?为什么我们不能在 pass 1 中构建工具,然后使用它们来构建gccglibclibstdc++等。

4

2 回答 2

15

目标是确保您的构建是一致的,无论您使用哪个编译器来编译您的编译器(以及编译器有哪些错误)。

假设您正在使用 gcc 3.2 构建 gcc 4.1(我将把它称为 gcc 3.2 “stage-0”)。为 gcc 4.1 进行 QA 的人在使用 gcc 4.1 以外的任何编译器构建时都没有测试它是否能正常工作——因此,需要首先构建一个 stage-1 gcc,然后使用那个 stage-1 来编译一个stage-2 compiler,以防止 stage-0 编译器中的任何错误影响最终结果。

然后,gcc 的默认编译过程使用 stage-2 编译器构建 stage-3 编译器,并比较两个二进制文件:它们之间的任何差异都可以用作存在 bug 的证明。

(当然,这只是一种避免意外错误的有效机制;请参阅经典的 Ken Thompson 论文Reflections on Trusting Trust讨论有意的错误如何在这种措施中幸存下来)。


这超越了 gcc 进入了整个工具链,因为相同的原则适用于整个工具链:如果您在运行 glibc-xy 的系统和运行 glibc-x.(y-1) 的系统上构建 glibc-xy 的结果有任何差异,并且您不要做额外的传递以确保您正在构建与您的目标环境匹配的内容,然后重现这些错误(并测试建议的修复)比其他情况要困难得多:没有人没有您的(通常未公开)构建环境必然会重新创建错误!

于 2016-10-05T21:28:45.593 回答
3

我知道这个查询有点老了,但我有一些东西要添加到答案中:澄清“引导程序”的含义。

多阶段构建的主要原因是从生成的软件中消除构建主机程序/配置/库的所有痕迹。编译新的软件是不够的。您还必须避免对主机的库、主机的内核接口(内核头文件)、主机的 pkg 版本以及对主机系统的所有其他此类依赖项的任何和所有引用。

假设你碰巧是一个受虐狂,想在 Fedora 27 上构建 Debian 4(应该可以)。简单地构建软件会引用 27 的库和其他东西。并且您的最终系统将无法运行,因为在安装最终系统时这些东西不可用。

LFS 通过在第 1 阶段构建简单的 x86 到 x86 binutils 和 gcc 交叉工具,然后安装要在最终系统中使用的内核头文件,然后是 glibc,在一定程度上简化了这个过程。第 2 阶段(binutils 和 gcc)是使用交叉工具构建的,这保证了主机的程序/libs/config 根本不被使用。工具链的其余部分(我称之为第 3 阶段)是使用第 2 阶段的工具构建的。现在可以构建最终阶段(进行一些小的调整),并确保不会引用或使用构建主机的任何部分,并且工具链的任何部分都不会被引用或使用。最后阶段是使用类似于 PATH=/bin:/usr/bin:/tools/bin; 的路径构建的。因此,随着最终工具的构建,它们将被使用,而不是工具链中的那些。

构建工具链不适合急躁的人。我花了几个月的时间来更新 Smoothwall Express 的构建系统和使用的 pkg,因为构建工具链充满了危险。我与许多龙、巴洛克人和矮人作战。我经常参考 LFS 来弄清楚他们是如何做到的。结果是一个自动化的可重入构建系统,它构建整个发行版而不引用主机系统。我主要在 Debian 8 上构建它,但众所周知它是在 Gentoo 上构建的,而且它应该能够在自身上构建。

于 2017-11-28T00:14:35.947 回答