天天看点

《Linux From Scratch》第二部分:准备构建 第五章:构建临时文件系统- 5.2 工具链技术备注

         本节解释总体构建方法之中的某些基本原理和技术细节。并不需要立即理解本节中的所有问题。在进行实际构建的过程中,绝大部分的信息将会变得愈加清晰。在该过程中可随时查阅本小节的内容。

《Linux From Scratch》第二部分:准备构建 第五章:构建临时文件系统- 5.2 工具链技术备注

在继续之前,请留意工作平台的名称,它通常称作目标系统三段式名称。目标系统三段式名称可通过运行脚本 config.guess

简单获得,许多软件的源码包都附带有该脚本(译者注:目标系统三段式名称描述了代码运行的平台,是GNU 构建系统中的一个核心概念,形如

i686-pc-gnu-linux。它包含三个字段:CPU家族/型号的名称(如 i686)、供应商(pc)和操作系统名称(如

gnu-linux)。更详细的信息请参阅 http://wiki.osdev.org/Target_Triplet)。解压 Binutils

源码包,执行其中的脚本:<code>./config.guess</code> 并查看其输出。例如,对于一个现代的 32 位英特尔处理器,其输出很可能为 i686-pc-linux-gnu。

还请留意平台的动态链接器的名称,它通常被称为动态加载器(不要与 Binutils 中的标准链接器 ld 混淆)。该动态链接器由 Glibc 提供,它寻找并加载程序所需的共享库,为程序运行作准备,并运行它。对于 32 位英特尔的机器,动态链接器的名称为 <code>ld-linux.so.2</code>。判断动态链接器的一个可靠方法是检查宿主系统中的任意一个二进制文件,执行:<code>readelf -l &lt;二进制文件名&gt; | grep interpreter</code> 且查看其输出。可在 Glibc 源码树的根目录下的 <code>shlib-versions</code> 文件中找到所有平台的权威参考。

通过改变 <code>LFS_TGT</code> 变量的目标系统三段式中的 “供应商” 字段,从而稍微调整工作平台的名称,以保证第一遍构建 Binutils 和 GCC 时能够生成兼容的交叉链接器和交叉编译器。此处的交叉链接器和交叉编译器生成的二进制文件与当前的硬件兼容,而不是用于其它的硬件架构。

临时库经交叉编译获得。由于交叉编译原本就不应该依赖于宿主系统,因此,通过降低宿主系统的头文件或库进入新工具的可能性,该方法可去除目标系统的可能污染。交叉编译的方式,还可以在 64 位硬件平台上同时构建出 32 位和 64 位库。

谨慎操作 GCC 源码,以告诉编译器将使用哪个目标系统动态链接器。

Binutils 是首个安装的包,这是因为执行 GCC 和 Glibc 的 configure

时都将进行有关汇编器和链接器的多项特性测试,以判断允许或禁用哪些软件特性。其重要性可能更甚于最初的意识。对 GCC 或 Glibc

的错误配置可能导致工具链出现难以捉摸的问题,可能直到整个构建过程接近尾声时才会显现出这些问题。通常情况下,一次测试套件失败可在你进行太多其它工作前暴露出该错误。

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

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

基于前述原因,这很重要。它还说明了 GCC 的配置脚本并不会搜索 PATH 目录来寻找使用什么工具。不过,在 gcc 自身的实际运行中,并不需要使用同样的搜索路径。运行:<code>gcc -print-prog-name=ld</code> 可获知 gcc 使用是何种标准链接器(LCTT 译注:<code>gcc -print-prog-name</code> 这个命令是为了显示 gcc 使用的某些内部工具的绝对路径,但事实上,ld 并不是 GCC 的内部工具,因此这条命令实际上没什么用)。

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

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

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

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

创建者:Gerard Beekmans

编辑者:Matthew Burgess 和 Armin K.

翻译团队:LCTT

译者/校对:Yuking-net,wxy

继续阅读