本节介绍总体构建方法背后的一些原理和技术细节。不必立即理解本节中的所有内容。在执行实际构建之后,大多数信息将变得更清晰。在本过程中的任何时候都可以参考本节。
第 5 章的总体目标是提供一个可以 chroot 进入的临时环境,并从中生成第 6 章中目标 LFS 系统的干净、无故障的构建。在此过程中,我们将新系统与宿主系统尽可能地分离,并在此过程中构建一个自包含和自托管的工具链。应该注意的是,构建过程旨在最大限度地降低新读者的风险,同时提供最大的教育价值。
在继续之前,请注意工作平台的名称,通常称为目标三元组。很多时候,目标三元组很可能是 i686-pc-linux-gnu。确定目标三元组名称的一个简单方法是运行许多软件包源代码附带的 config.guess 脚本。解压 Binutils 源代码并运行脚本:./config.guess 并记下输出。
还要注意平台动态链接器的名称,通常称为动态加载器(不要与作为 Binutils 一部分的标准链接器 ld 混淆)。Glibc 提供的动态链接器查找并加载程序所需的共享库,准备程序运行,然后运行它。动态链接器的名称通常是ld-linux.so.2。在不太常见的平台上,名称可能是ld.so.1,而较新的 64 位平台可能会被命名为完全不同的名称。平台动态链接器的名称可以通过查看/lib目录来确定。确定名称的可靠方法是通过运行以下命令检查宿主系统中的随机二进制文件:readelf -l <二进制文件名> | grep interpreter 并记下输出。涵盖所有平台的权威参考资料在 Glibc 源代码树根目录下的shlib-versions文件中。
关于第 5 章构建方法如何工作的一些关键技术要点
该过程在原理上类似于交叉编译,其中安装在相同前缀中的工具协同工作,因此利用了一点 GNU “魔法”
仔细操作标准链接器的库搜索路径可确保程序仅链接到选定的库
仔细操作 gcc 的specs文件会告诉编译器将使用哪个目标动态链接器
首先安装 Binutils,因为 GCC 和 Glibc 的 configure 运行都会对汇编器和链接器执行各种功能测试,以确定启用或禁用哪些软件功能。这比人们最初意识到的更重要。配置不正确的 GCC 或 Glibc 可能会导致工具链出现细微的损坏,这种损坏的影响可能要到整个发行版的构建接近尾声时才会显现出来。测试套件失败通常会在执行过多额外工作之前突出显示此错误。
Binutils 在两个位置安装其汇编器和链接器,/tools/bin和/tools/$TARGET_TRIPLET/bin。一个位置中的工具硬链接到另一个位置。链接器的一个重要方面是其库搜索顺序。可以通过将 --verbose 标志传递给 ld 来获得详细信息。例如,ld --verbose | grep SEARCH 将说明当前的搜索路径及其顺序。它通过编译一个虚拟程序并将 --verbose 开关传递给链接器来显示 ld 链接了哪些文件。例如,gcc dummy.c -Wl,--verbose 2>&1 | grep succeeded 将显示链接期间成功打开的所有文件。
下一个安装的软件包是 GCC。在运行 configure 期间可以看到的一个例子是
checking what assembler to use... /tools/i686-pc-linux-gnu/bin/as checking what linker to use... /tools/i686-pc-linux-gnu/bin/ld
这对于上面提到的原因很重要。这也表明 GCC 的 configure 脚本不会搜索 PATH 目录来查找要使用的工具。但是,在 gcc 本身的实际操作期间,不一定使用相同的搜索路径。要查找 gcc 将使用哪个标准链接器,请运行:gcc -print-prog-name=ld。
可以通过在编译虚拟程序时将 -v 命令行选项传递给 gcc 来获得详细信息。例如,gcc -v dummy.c 将显示有关预处理器、编译和汇编阶段的详细信息,包括 gcc 的包含搜索路径及其顺序。
下一个安装的软件包是 Glibc。构建 Glibc 最重要的考虑因素是编译器、二进制工具和内核头文件。编译器通常不是问题,因为 Glibc 将始终使用在PATH目录中找到的 gcc。二进制工具和内核头文件可能会稍微复杂一些。因此,不要冒险,并使用可用的 configure 开关来强制执行正确的选择。在运行 configure 之后,检查config.make文件glibc-build目录中的 config.make 文件内容,以获取所有重要详细信息。请注意,使用 CC="gcc -B/tools/bin/" 来控制使用哪些二进制工具,并使用 -nostdinc 和 -isystem 标志来控制编译器的包含搜索路径。这些项目突出了 Glibc 软件包的一个重要方面——就其构建机制而言,它是非常自给自足的,并且通常不依赖于工具链默认值。
在安装 Glibc 之后,进行一些调整以确保搜索和链接仅在/tools前缀内进行。安装一个调整后的 ld,它具有硬连线的搜索路径,仅限于/tools/lib。然后修改 gcc 的 specs 文件,以指向/tools/lib中的新动态链接器。这最后一步对于整个过程至关重要。如上所述,动态链接器的硬连线路径嵌入到每个可执行和链接格式 (ELF) 共享可执行文件中。可以通过运行以下命令来检查这一点:readelf -l <二进制文件名> | grep interpreter。修改 gcc 的 specs 文件可确保从此处到本章末尾编译的每个程序都将使用/tools/lib.
中的新动态链接器。需要使用新动态链接器也是为什么为 GCC 的第二遍应用 Specs 补丁的原因。如果不这样做,将导致 GCC 程序本身具有来自宿主系统的/lib目录嵌入到其中,这将达不到摆脱宿主的目标。
在 Binutils 的第二遍过程中,我们能够利用 --with-lib-path configure 开关来控制 ld 的库搜索路径。从那时起,核心工具链是自包含和自托管的。第 5 章的其余软件包都针对/tools.
中的新 Glibc 构建。在第 6 章中进入 chroot 环境后,由于其上述自给自足的性质,要安装的第一个主要软件包是 Glibc。一旦将此 Glibc 安装到/usr中,快速切换工具链默认值,然后继续构建其余的目标 LFS 系统。