为什么要从头开始构建 Linux(LFS)?

why multiple passes for building Linux From Scratch (LFS)?

我正在尝试理解 Linux From Scratch 的概念,并且想知道为什么有多个通道用于构建 binutilsgcc

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

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

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

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

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


这超越了 gcc 进入整个工具链,因为相同的原则贯穿始终:如果您在系统 运行 glibc-[=33 上构建 glibc-x.y 的结果有任何差异=] 和系统 运行 glibc-x.(y-1) 而你 不要 做额外的传递以确保你正在为你的匹配构建目标环境,然后重现这些错误(并测试建议的修复)比其他情况要困难得多:没有你的(通常未公开的)构建环境的人不一定能重现错误!

我知道这个查询有点老,但我有一些要补充的答案:澄清 'bootstrap' 的含义。

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

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

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

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