|
| 1 | + |
| 2 | +# 工具链技术说明 |
| 3 | + |
| 4 | +本节阐述了整个构建方法的一些基本原理和技术细节, 你不必马上就理解本节中的所有内容。在实际操作之后,你就会了解大多数的东西。你可以在任何时候回顾本节。 |
| 5 | + |
| 6 | +第五章的总体目标是构建一个临时区域,它包含一些正确安装的且与宿主系统分离的工具。通过在这个临时环境中使用```chroot```,来确保一个干净的,没有问题的LFS目标系统构建流程。这个构建过程被设计为尽量减少新手犯错误的可能, 同时尽可能多的提供教育价值。 |
| 7 | + |
| 8 | +>注意 |
| 9 | +>在继续之前,要先知道工作平台的名称,即所谓的"target triplet"(目标三元组)。要确定 target triplet 的名称, 有一个简单的方法, 就是运行许多源码包里都有的 config.guess 脚本。解开 Binutils 的源码包,然后运行脚本 ```./config.guess```并注意输出的内容。例如, 最新的32位Intel 处理器的输出类似于 i686-pc-linux-gnu。 |
| 10 | +>同时也要知道工作平台的动态链接器名称,这里指的是动态加载器(不要与 Binutils 里的 标准链接器 ld 混淆了)。动态链接器由 Glibc 提供, 用来找到并加载一个 程序运行时 所需的共享库, 在做好程序运行的准备之后,运行这个程序。32位Intel电脑的动态连 接器的名称通常是 ld-linux.so.2。确定这个名称还有一个必杀技, 就是在宿主系统 上随便找一个二进制文件,运行 ```readelf -l <二进制文件名> | grep interpreter```并查看输出的内容。涵盖所有平台的权威参考请查看 Glibc 源码根目录里的 shlib-versions 文件。 |
| 11 | +
|
| 12 | +关于 Chapter 5 中构建方法如何工作的一些技术要点: |
| 13 | + |
| 14 | +1. 通过改变 LFS_TGT 变量的“vendor”字段,稍微调整工作平台的名字,来确定第一遍安装的Binutils 和 GCC 生成了一个兼容的交叉连接器和交叉编译器。 交叉链接器和交叉编译器会产生兼容当前硬件的二进制文件,而不是另一个架构的二进制文件。 |
| 15 | +2. 临时库文件是交叉编译的, 因为本地的交叉编译器不能对宿主系统有任何依赖关系,所以本方法通过减少宿主系统的头文件或库进入新工具链的机会,消除了对目标系统的潜在污染。 交叉编译还使在64位硬件上创建32位和64位库文件成为可能性。 |
| 16 | +3. 小心处理 gcc 的 specs 文件,该文件告诉编译器要使用哪个动态连接器。 |
| 17 | + |
| 18 | +首先安装的是 Binutils, 因为 GCC 和 Glibc 运行的 configure 文件要在汇编器和联接器上执行各种各样的特性测试, 以确定软件的哪些功能要启用, 哪些功能要禁用。这样做比你想像的还要重要,配置不正 确的 GCC 或者 Glibc 会导致工具链出现微妙的错误,这样的错误造成的影响可能直到整个系统快要编译 完成的时候才显现出来。 测试程序通常会在其它的许多工作进行之前给出错误警告 。 |
| 19 | + |
| 20 | +Binutils 将它的汇编器和链接器安装在两个位置: ```/tools/bin``` 和 ```/tools/$LFS_TGT/bin```。 一个位置的工具是另外一个位置的硬链接。 连接器的一个重要用途是它的库搜索顺序,将 --verbose 参数传递给 ld 可以获得详细的信息。比如,输入 ```ld --verbose | grep SEARCH``` 将显示当前搜索路径和顺序。要显示 ld 连接的是哪些文件,可以编译一个伪(dummy)程序并把 --verbose 参数传递给连接器。例如,输入 ```gcc dummy.c -Wl,--verbose 2>&1 | grep succeeded``` 将显示所有连接过程中成功打开的文件。 |
| 21 | + |
| 22 | +第二个安装的软件包是 GCC。 下面是运行 configure 脚本时,输出内容的一个示例: |
| 23 | + |
| 24 | +``` |
| 25 | +checking what assembler to use... /tools/i686-lfs-linux-gnu/bin/as |
| 26 | +checking what linker to use... /tools/i686-lfs-linux-gnu/bin/ld |
| 27 | +``` |
| 28 | + |
| 29 | +基于上面提到过的原因,这是重要的步骤,它同时证明了 GCC 的配置脚本并不是搜索 PATH 里的目录来寻找要使用哪个工具的,而且,在 gcc 的实际操作中, 不必使用相同的搜索路径。 要知道 gcc会使用哪个标准连接器,请运行命令:```gcc -print-prog-name=ld```。 |
| 30 | + |
| 31 | +在编译一个伪程序的时候,给 gcc 命令传递 -v 选项可以获得详细的信息。举个例子: ```gcc -v dummy.c``` 将显示在预处理、编译和汇编各个阶段的详细信息,包括 gcc文件包含的搜索路径及其顺 |
| 32 | +序。 |
| 33 | + |
| 34 | + |
| 35 | +第三个要安装的是Linux的API头文件,它使得标准C库(Glibc)可以使用Linux内核提供的功能。 |
| 36 | + |
| 37 | +接下来安装的软件包是 Glibc。编译 Glibc 的时候, 最需要注意的地方是编译器、 二进制工具(Binutils)和内核头文件。编译器一般不是问题, 因为 Glibc 总是将与编译器相关的 --host 参数传递给它的配置脚本,在我们的例子里就是 i686-lfs-linux-gnu-gcc, 而二进制工具和内核头文件可能有点复杂。因此, 为慎重起见, 要使用可用的配置开关(选项)来强制进行正确的选择。在运行 configure 之后,请检查 glibc-build 目录下的 config.make 文件的内容,查看所有重要的细节。 注意 CC="i686-lfs-gnu-gcc"的作用是控制要使用哪个二进制工具; 而 -nostdinc 和 -isystem 参数则是用来控制编译器的 include 搜索路径。 这些选项表明了 Glibc 软件包的一个重要特征:根据其编译机器的情况, 它是非常自给自足的, 而且一般不依赖于工具链的默认值。 |
| 38 | + |
| 39 | +第二遍编译 Binutils 的过程中,我们利用 --with-lib-path 选项来控制 ld 的库搜索路径。 |
| 40 | + |
| 41 | +对于第二遍编译 GCC,为了告诉GCC使用新的动态连接器,它的源代码也需要改变。 不这样做的 结果是 GCC 会把宿主系统 /lib 目录下动态连接器的名字嵌入进来, 这样有悖于与宿主系统隔离的目标。从此刻起,核心工具链便是自我独立的了。第五章后续的软件包都将由在```/tools```中的新Glibc构建。 |
| 42 | + |
| 43 | +在 Chapter 6 中进入 chroot 环境后,第一个安装的主要软件包就是 Glibc, 原因是上面所提 到的 Glibc 自给自足的特性。 一旦 Glibc 安装到 /usr 目录后, 我们会马上改变工具链的默认 值, 然后构建目标 LFS 系统的其它部分。 |
0 commit comments