5.2. 工具链技术说明

这一节解释总体构建方法之中的某些基本原理和技术细节。本节中的所有问题并无需马上消化。在进行实际构建的过程中,绝大部分的信息会变得愈加清晰。过程中随时都可以查阅本小节的内容。

纵览 第 5 章 的目标是生成一个临时的系统,这个系统中包含一个已知的较好工具集,并且工具集可以独立于宿主系统。通过使用 chroot,其余各章中的命令将被包含在此环境中,以保证目标 LFS 系统能够洁净且无故障地生成。该构建过程的设计就是为了使得新读者承担最少的风险,同时还能有最好的指导价值。

[注意]

注意

在继续前,请留心工作平台的名称,它时常被称为目标三元组。要确定目标三元组的名称有一个简单的法子,那就是运行许多软件包的源码附带的脚本 config.guess。解压 Binutils 的源码并运行脚本:./config.guess 并注意它的输出。举一个例子,Intel 的 32 位处理器输出会是 i686-pc-linux-gnu。而在一个 64 位系统上,则会是 x86_64-pc-linux-gnu

也请留心平台的动态链接器的的名称,它时常被称为动态加载器(不要与 Binutils 中的标准链接器 ld 混为一谈)。动态链接器由 Glibc 提供,用于寻找和加载程序所需的共享库,为程序的运行做准备,以及运行程序。32 位的 Intel 机器,动态链接器的名称是 ld-linux.so.2(64 位系统则是 ld-linux-x86-64.so.2)。确定动态链接名的一个确定的方法,就是检查随机二进制文件,通过在宿主机运行:readelf -l <name of binary> | grep interpreter 并注意它的输出。覆盖全平台的权威参考在 Glibc 源码树根目录的 shlib-versions 文件中。

下面是 第 5 章 构建方法的几个关键技术点:

Binutils 是首个安装的包,因为无论是执行 GCC 还是 Glibc 的 configure 时,都将围绕关汇编器和链接器实施多项特性测试,来判断哪些软件特性要启用或是禁用。其重要性可能更甚于你对它的第一印象。GCC 或 Glibc 的错误配置会导致工具链出现难以捉摸的问题,可能直到整个构建过程接近尾声时,这些问题才会显现出来。不过,通常情况下,在你进行大量的无用功之前,一次测试套件的失败便会将该错误高亮出来。

Binutils 将其汇编器和链接器安装在两处,/tools/bin/tools/$LFS_TGT/bin。有一处的工具是另一处的硬链接。链接器的一个重要方面是它的库搜索顺序。可以给 ld 传递参数 --verbose 获取详细信息。例如,ld --verbose | grep SEARCH 将说明当前的搜索路径及其顺序。通过编译一个 dummy(假)程序并向链接器传递 --verbose 参数,可显示 ld 都链接了哪些文件。例如,gcc dummy.c -Wl,--verbose 2>&1 | grep succeeded 将显示链接过程中成功打开的所有文件。

下一个安装的包是 GCC。下面便是运行 GCC 的 configure 的输出示例:

checking what assembler to use... /tools/i686-lfs-linux-gnu/bin/as
checking what linker to use... /tools/i686-lfs-linux-gnu/bin/ld

基于上述原因,这很重要。这还说明了 GCC 的配置脚本并不会搜索 PATH 目录来寻找使用什么工具。不过,在 gcc 自身的实际运行中,并不需要使用同样的搜索路径。运行:gcc -print-prog-name=ld 可获知 gcc 使用是何种标准链接器。

在编译 dummy(假)程序时,向 gcc 传递命令行选项 -v 可获得详细信息。例如,gcc -v dummy.c 将显示预处理器、编译和汇编阶段的详细信息,包括 gcc 的 include 搜索路径及其顺序。

下一个安装的是经过净化的 Linux API 头文件。这些头文件可使得标准 C 库(Glibc)与 Linux 内核提供的特性进行交行交互。

下一个安装的软件包是 Glibc。构建 Glibc 时,最重要的几个注意点是编译器、二进制工具和内核头文件。编译器通常不成问题,因为 Glibc 将一直使用传递给它配置脚本的,有关 --host 参数的编译器。如,在我们的这个场景中,编译器就是 i686-lfs-linux-gnu-gcc。而二进制工具和内核头文件可能就要复杂一些了。因此,请不要冒险,并利用可用的配置开关来强制正确的选择。configure 运行完毕,目录 glibc-build 下的文件 config.make 包含有所有的重要细节。需要注意的是,CC="i686-lfs-gnu-gcc" 用来控制使用哪个二进制工具,-nostdinc-isystem 标志用来控制编译器的 include 搜索路径。这些条目强调了 Glibc 包的一个重要方面,即其构建机制是非常自给自足的,通常并不依赖默工具链的默认设置。

在第二遍编译 Binutils 过程中,我们能够利用配置开关 --with-lib-path 来控制 ld 的库搜索路径。

第二遍编译 GCC 时,也需要修改其源代码,以告诉 GCC 使用新的动态链接器。如果不加修改,将导致 GCC 的自身程序中嵌入源自宿主系统目录 /lib 中的动态链接器,这违背了独立于宿主系统的目的。正是基于前面的这个出发点,核心工具链是自包含和自托管的。第 5 章 其它的软件包都将在 /tools 中的新 Glibc 的基础上进行构建。

在进入 第 6 章中的 chroot 环境前,将安装的首个主要的软件包是 Glibc,这是因为它天生具有前面提及的自给自足特点。一旦将 Glibc 安装到 /usr 中,我们将快速改变工具链的默认设置,然后继续构建目标 LFS 系统的其余部分。