4.5. 关于 SBU 许多人都想知道编译和安装一个软件包预计需要多长时间。因为 Linux From Scratch 可以在多种不同的系统上创建,准确估计所需的时间是不可能的。最快的系统上编译安装{zd0}的软件包(Glibc)大约需要 20 分钟,但在很慢的系统上可能耗费长达三天时间。我们不提供准确时间,代之以标准编译时间单位(SBU)来度量。 SBU 度量具体说明如下,本书中{dy}个编译的软件包是第五章中静态编译的 Binutils。编译这个软件包所花费的时间就作为标准编译时间单位(SBU)。所有其它软件的编译时间都用这个时间来衡量。 例如,对于一个编译时间为 4.5 SBU 的软件包,这意味着如果一个系统静态编译安装 Binutils 需要花费 10 分钟,那么编译这个软件包将大约需要 45 分钟。幸运的是,大多数软件包编译安装所需的时间都比 Binutils 所需的时间要短。 通常,SBU 并不十分xx,因为它依赖于许多因素,包括宿主系统 GCC 的版本。另外,在基于对称多处理器(SMP)的机器上,SBU 更加不准确。我们提供 SBU,仅仅是给出安装一个软件包所需时间的大概估计,在某些情况下实际花费的时间与预估计的时间之间可能有数十分钟的差异。 要查看在一些特定机器上的实际编译安装时间,我们推荐您查看 LinuxFromScratch SBU 的主页 http://www.linuxfromscratch.org/~sbu/。 4.6. 关于测试套件 大多数软件包提供了测试套件。编译完一个软件包之后立即运行一下它提供的测试程序是个好主意,因为测试程序将进行一次“健全检查”来确认所有的代码是否都正确编译了。通过了测试套件的一系列检查,通常意味着软件包在按照开发者的预期工作,但是这并不保证这个软件包就xx没有 bug 了。 某些软件包的测试程序是极为重要的,例如核心工具链软件包—GCC、Binutils、Glibc—的测试程序,这是因为这些软件包在一个良好工作的系统里的处于核心角色。GCC 和 Glibc 的测试程序需要运行很长时间,尤其在速度慢的硬件上,但我们仍然强烈建议您运行这些测试程序。 [注意] 注意 经验显示,运行第五章的测试套件收获很小。宿主系统会不可避免的对该章中的测试造成影响,经常会有不能解释的错误。因为第五章中编译的工具是临时的,会最终被丢弃,因此我们推荐一般水平的读者不需再做该章的测试。这些测试程序的指令是为开发和测试人员准备的,它们不是必需的。 Binutils 和 GCC 的测试程序一个常见的问题就是没有可用的伪终端(PTY),这样可能会出现大量的测试失败。可能的原因有几个,但最可能的原因是宿主系统没有正确的设置好 devpts 文件系统,这个问题会在第五章详细讨论。 某些软件包测试程序可能会出错,但是开发者了解到这些,这些出错关系不是很大。请参考 LFS Wiki(地址为http://www.linuxfromscratch.org/lfs/build-logs/6.4/)查看这些出错是否在预料之中。这个站点的内容适用于本书所有的测试。 5. 构建临时系统 目录 * 本章介绍 * 工具链技术说明 * 基本编译规则说明 * Binutils-2.18 - {dy}遍 * GCC-4.3.2 - {dy}遍 * Linux-2.6.27.4 API 头文件 * Glibc-2.8-20080929 * 调整工具链 * Tcl-8.5.5 * Expect-5.43.0 * DejaGNU-1.4.4 * GCC-4.3.2 - 第二遍 * Binutils-2.18 - 第二遍 * Ncurses-5.6 * Bash-3.2 * Bzip2-1.0.5 * Coreutils-6.12 * Diffutils-2.8.1 * E2fsprogs-1.41.3 * Findutils-4.4.0 * Gawk-3.1.6 * Gettext-0.17 * Grep-2.5.3 * Gzip-1.3.12 * M4-1.4.12 * Make-3.81 * Patch-2.5.4 * Perl-5.10.0 * Sed-4.1.5 * Tar-1.20 * Texinfo-4.13a * Util-linux-ng-2.14.1 * 清理系统 * 改变所有者 5.1. 本章介绍 本章介绍如何构建一个极小的 Linux 系统,这个系统将仅包含用于构建第六章的 LFS 系统的必要的工具和一个足够便利的工作环境。 构建这个环境分两个步骤。{dy}步建立一个新的依赖于宿主系统的工具链,包括编译器、汇编器、链接器、库文件和一些实用工具;第二步是利用这些工具链构建其它的必要工具。 本章中编译安装的文件将安装在 $LFS/tools 目录下。这样可以与下一章将要安装的软件以及宿主系统区分开来。这些软件包编译出来是起临时作用的,我们不希望这些软件和即将建立的 LFS 系统混杂在一起。 * 上一页 构建临时系统 * 下一页 工具链技术说明 * 上一级 5.2. 工具链技术说明 本节阐述了整个构建方法的一些基本原理和技术细节,您不必马上就理解本节中的所有内容。在您实际操作之后,就会了解大多数的东西,您可以在任何时候回顾本节。 第五章的总体目标是提供一个临时环境,您可以通过 chroot 进入到这个环境,在里面构建一个第六章的干净、没有问题的目标 LFS 系统。为了尽量的与宿主系统分开,我们一步步构建了一个自包含、自依赖的工具链。这个构建过程对于新手而言犯错误的风险已被降到{zd1},同时它也提供了尽量大的学习价值。 [重要] 重要 在继续之前,要先知道工作平台的名称,就是所谓的目标三元组(“target triplet”)。通常情况下,目标三元组可能是 i686-pc-linux-gnu。确定该名字的简单办法就是运行许多源码包中都含有的 config.guess脚本,解压 Binutils 包运行 ./config.guess 并注意输出结果。 另外,注意工作平台的动态连接器名称,通常指的是动态加载器(不要与 Binutils 里面的标准连接器 ld 相混淆)。动态连接器由 Glibc 提供,用来找到并加载一个程序运行时所需的共享库,在做好程序运行的准备之后,运行这个程序。动态连接器的名称通常是 ld-linux.so.2。在不怎么流行的平台上则可能是 ld.so.1,而在新的 64 位平台上更可能是别的xx不同的名称。通过查看宿主系统的 /lib 目录可以确定动态连接器的名字。确定这个名称还有一个必杀技,就是在宿主系统上随便找一个二进制文件,运行 readelf -l <name of binary> | grep interpreter 并查看输出的内容。涵盖所有平台的xx参考请查看 Glibc 源码根目录里的 shlib-versions 文件。 以下是关于第五章中构建方法的一些技术要点: * 这个过程在原理上与交叉编译类似,通过安装在同一个目录的工具的协同工作,它还利用了一点 GNU 的“魔术”。 * 小心处理标准连接器的库文件搜索路径,确保程序仅连接到指定的库上。 * 小心处理 gcc 的 specs 文件,告诉编译器要使用哪个动态连接器。 首先安装的是 Binutils ,因为 GCC 和 Glibc 的 configure 脚本要在汇编器和连接器上执行各种各样的特性测试,以确定软件的哪些功能要启用或禁用。这样做比你想像的还要重要,配置不正确的 GCC 或者 Glibc 会导致工具链出现微妙的错误,这样的错误造成的影响可能直到整个系统快要编译完成的时候才显现出来。测试程序通常会在其它的许多工作进行之前给出错误警告 (以避免其后的无效劳动)。 Binutils 的汇编器和连接器安装在两个位置: /tools/bin 和 /tools/$TARGET_TRIPLET/bin。其中一个程序是另外一个的硬连接。连接器的一个重要方面是它的库搜索顺序,将 --verbose 选项传递给 ld 可以获得详细的信息。比如:ld --verbose | grep SEARCH 将显示当前搜索路径和顺序。要显示 ld 连接的是哪个文件,可以编译一个伪(dummy)程序并把 --verbose 传递给连接器。例如:gcc dummy.c -Wl,--verbose 2>&1 | grep succeeded 将显示所有连接成功的文件。 接下来安装的是 GCC 。下面是运行 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 的配置脚本并不是搜索 PATH 里的目录来寻找要使用哪个工具的,而且在 gcc 的实际操作中也不一定会使用相同的搜索路径。想要知道 gcc 将会使用哪个标准连接器,请运行 gcc -print-prog-name=ld。 通过在编译一个伪程序传递参数 -v 给 gcc 可以获得详细的信息。举例来说,gcc -v dummy.c将会给出在预处理、编译和汇编各个阶段的详细信息,包括 gcc 包含的搜索路径及其顺序。 下一个安装的包是 Glibc。编译 Glibc 的时候,最需要注意的地方是编译器、Binutils 和内核头文件。编译器一般不是问题,因为 Glibc 总是使用在 PATH 目录里找到的 gcc;Binutils 和内核头文件要复杂点。因此,为慎重起见,明确使用配置开关(选项)来强制进行正确的选择。在运行 configure 脚本之后,检查在 glibc-build 目录下的 config.make 文件,注意所有重要的细节信息。CC="gcc -B/tools/bin/" 控制着使用哪一个 Binutils,而用选项 -nostdinc 和 -isystem 用来控制编译器的库文件的搜索路径。这些说明了 Glibc 的一个重要方面——在编译方法上它是高度自给自足的,通常不依赖于工具链的默认值。 在安装完 Glibc 之后,需要做一些调整来保证 /tools 是{wy}的搜索和连接路径。安装一个调整好的 ld 它的硬链接搜索路径限制在 /tools/lib。接下来修正 gcc 的 specs 文件,使它指向新的位于 /tools/lib 的动态连接器。{zh1}一步对于整个过程至关重要,正如先前提及的,指向动态连接器的硬链接路径被嵌入到每个共享 ELF 可执行文件里。这可以通过 readelf -l <name of binary> | grep interpreter 来查看。修正 gcc 的 specs 文件确保了现在开始到本章结束编译的所有程序都会使用位于 /tools/lib 下的新动态连接器。 在第二遍编译 GCC 时,也需要修改其源码使 GCC 使用新生成的动态连接器。不这样做的结果是 GCC 会把宿主系统 /lib 目录下动态连接器的名字嵌入进来,这样有悖于与宿主系统隔离的目标。 在第二遍编译 Binutils 时,我们可以利用参数 --with-lib-path 来控制 ld 的库文件搜索路径。如前面所指出的,核心工具链是自给自足的,第五章剩余部分的所有软件包在编译时都会使用位于 /tools 目录下的新 Glibc。 基于上述 Glibc 自给自足的特性,当我们进入 chroot 虚拟环境之后,在第六章中首先安装就是 Glibc。一旦安装好 Glibc 到 /usr,马上更改工具链的默认值,然后继续构建目标 LFS 系统的剩余部分。 5.3. 基本编译规则说明 在编译软件包时有一些假定,说明如下: * 有些软件包在编译之前需要打补丁,但是仅仅在需要修正一个问题的时候才会打该补丁。一个补丁可能在本章和下一章都需要,但有时会只在这章或下章需要,因此会发现已经下载了的补丁在编译时没有应用,此时不必有太多顾虑。在应用某个补丁时可能会出现 offset 或 fuzz 的警告信息,不要在意这些警告,这些补丁仍能成功被应用。 * 在编译大多数软件包的时候,会出现一些警告信息。这是很正常的,可以安全的忽略掉。这些警告大都分是关于警告 C 或 C++ 使用了不推荐(deprecated)但仍有效的语法。C 语言的标准会经常更改,某些软件包使用了旧的标准,这不算问题,但是会给出警告信息。 [重要] 重要 在每个软件包安装好以后,删除它的源码和编译目录,另有特殊说明除外。删除源码可以防止同一个软件包再次编译安装时配置出错。 * 再次检查 LFS 变量是否设置正确。 echo $LFS 确认输出结果为 LFS 分区的挂载点,在我们的配置中是 /mnt/lfs。 * {zh1}一个重要的事项要着重指出: [重要] 重要 在安照说明编译安装软件包之前,每个源码包应该作为 lfs 用户解压,而且进入(cd)到新生成的目录中。编译说明假设使用 bash Shell。 5.4. Binutils-2.18 - {dy}遍 Binutils 是一组开发工具,包括连接器、汇编器和其他用于目标文件和档案的工具。 预计编译时间: 1 SBU 所需磁盘空间: 213 MB 5.4.1. 安装 Binutils 首先安装的{dy}个软件包是 Binutils ,这非常重要。因为 Glibc 和 GCC 会针对可用的连接器和汇编器进行多种测试,以决定是否打开某些特性。 Binutils 不能识别高于 4.9 版本的 Texinfo。应用下面的补丁修正这个问题: patch -Np1 -i ../binutils-2.18-configure-1.patch Binutils 的文档推荐用一个新建的目录来编译它,而不是在源码目录中: mkdir -v ../binutils-build cd ../binutils-build [注意] 注意 如果你想使用本书余下部份列出的 SBU 值,那么现在就要测量一下编译本软件包的时间。你可以用类似下面这样的time 命令来测量:time { ./configure ... && make && make install; } 现在开始准备编译: CC="gcc -B/usr/bin/" ../binutils-2.18/configure \ --prefix=/tools --disable-nls --disable-werror 配置选项的含义: CC="gcc -B/usr/bin/" 该选项强制 gcc 使用宿主系统中 /usr/bin 目录下的连接器。这样做的必要是因为新生成的 ld 可能与某些宿主系统的 gcc 不兼容。 --prefix=/tools 这个参数告诉配置脚本,应该把 Binutils 软件包中的程序安装到 /tools 目录中。 --disable-nls 这个参数禁用国际化(通常简称 i18n),临时工具不需要国际化的特性。 --disable-werror 该参数防止编译工作在使用某些宿主系统的编译器给出警告信息时停止。 接下来编译它: make 现在编译完成了。通常我们会运行测试套件,但是目前测试套件(Tcl、Expect 和 DejaGNU)尚未安装。而且在这里运行测试也没什么用处,因为{dy}遍安装的程序很快就会被第二遍的程序所覆盖。 安装它: make install 下面为后面“调整工具链”做准备: make -C ld clean make -C ld LIB_PATH=/tools/lib cp -v ld/ld-new /tools/bin make 选项的含义: -C ld clean 告诉 make 程序删除所有 ld 子目录中编译生成的文件。 -C ld LIB_PATH=/tools/lib 这个选项重新编译 ld 子目录中的所有文件。在命令行中指定 Makefile 的 LIB_PATH 变量值,使它明确指向临时工具目录,以覆盖默认值。这个变量的值指定了连接器的默认库搜索路径,它在这一章的稍后部分会用到。 关于这个软件包的详细资料位于第 6.11.2 节 “Binutils 的内容”。 5.5. GCC-4.3.2 - {dy}遍 GCC 软件包包含 GNU 编译器,其中有 C 和 C++ 编译器。 预计编译时间: 22 SBU 所需磁盘空间: 1.1 GB 5.5.1. 安装 GCC 该版本的 GCC 需要 GMP 和 MPFR 软件包,你的宿主系统上可能没有安装这两个软件包,它们将一起编译进 GCC。 tar -jxf ../mpfr-2.3.2.tar.bz2 mv mpfr-2.3.2 mpfr tar -jxf ../gmp-4.2.4.tar.bz2 mv gmp-4.2.4 gmp GCC 的安装指南推荐用一个新建的目录来编译它,而不是在源码目录中: mkdir -v ../gcc-build cd ../gcc-build 准备编译 GCC: CC="gcc -B/usr/bin/" ../gcc-4.3.2/configure --prefix=/tools \ --with-local-prefix=/tools --disable-nls --disable-shared --disable-libssp \ --enable-languages=c 配置选项的含义: CC="gcc -B/usr/bin/" 该选项强制 gcc 使用宿主系统中 /usr/bin 目录下的连接器。这样做的必要是因为上一节新生成的 ld 可能与某些宿主系统的 gcc 不兼容。 --with-local-prefix=/tools 这个参数的目的是把 /usr/local/include 目录从 gcc 的 头文件搜索路径里删除。这并不是{jd1}必要,但能尽量减小宿主系统的影响。 --disable-shared 该开关强制 GCC 静态链接中间库,这样做是为了避免宿主系统可能带来的错误。 --disable-libssp 该开关是为了防止和旧版本的 glibc 的冲突,该冲突可能导致编译失败。 --enable-languages=c 该选项确保只编译 C 语言的编译器,现在我们只需要 C。 下面的命令会不只一次的编译 GCC,它会使用{dy}遍编译的程序来编译第二次,再利用第二次的结果进行第三次编译。然后对第二次和第三次的结果进行比较,确保能xx无差错的编译自身。这被称作“bootstrapping”。这样编译 GCC 可以保证其正确性。有了软件包的配置文件,运行下面命令进行下一步的编译: make 编译完成之后,按通常情况要运行测试程序,但是如前面所述,测试框架还没有就位。在这里运行测试没什么用处,因为{dy}遍安装的程序很快就会被第二遍的程序所覆盖。 安装软件包: make install 使用参数 --disable-shared 意味着文件 libgcc_eh.a 不会被编译和安装,而在编译 Glibc 时,由于使用了参数 -lgcc_eh,这会依赖 libgcc_eh.a 库。我们可以创建一个到 libgcc.a 的符号链接来满足这一依赖关系,因为该文件中通常包含了 libgcc_eh.a 中的内容。 ln -vs libgcc.a `gcc -print-libgcc-file-name | \ sed 's/libgcc/&_eh/'` {zh1},我们创建一个必要的符号连接。因为许多程序和脚本运行 cc 而不是 gcc,这是为了保持程序的通用性,使得在一些没有安装 GCC 的 UNIX 系统上也能运行。运行 cc 可以使系统管理员自由选择使用系统中不同的 C 语言编译器。 ln -vs gcc /tools/bin/cc 关于这个软件包的详细资料位于第 6.14.2 节 “GCC 的内容”。 5.6. Linux-2.6.27.4 API 头文件 Linux API Headers 是将内核的应用程序编程接口(API)提供给 Glibc 使用。 预计编译时间: 0.1 SBU 所需磁盘空间: 341 MB 5.6.1. Linux API 头文件的安装 Linux 内核需要向系统 C 语言库(LFS 中为 Glibc)使用的应用程序接口(API)。我们通过安装 Linux 内核源码包中的 C 语言头文件来实现。 首先,确认使没有上次使用留下来的过时的文件和依赖关系。 make mrproper 现在测试并提取源码包中的用户可见内核头文件,它们被放置在一个本地的中间目录,然后复制到所需的位置。整个提取过程会移动目标目录的任何文件。 make headers_check make INSTALL_HDR_PATH=dest headers_install cp -rv dest/include/* /tools/include 关于这个软件包的详细资料位于第 6.7.2 节 “Linux API Headers 的内容”。 5.7. Glibc-2.8-20080929 Glibc 包含了主要的 C 语言库。这个库提供了基本例程,用于分配内存、搜索目录、打开关闭文件、读写文件、字串处理、模式匹配、数学计算等等。 预计编译时间: 7.6 SBU 所需磁盘空间: 407 MB 5.7.1. Glibc 的安装 如果宿主系统使用 /etc/ld.so.preload,运行下面命令修正可能会出现的问题。 sed -i 's@/etc/ld.so.preload@/tools/etc/ld.so.preload@' elf/rtld.c Glibc 文档推荐在源码目录之外的一个专门的编译目录下进行编译: mkdir -v ../glibc-build cd ../glibc-build 由于 Glibc 不再支持 i386,Glibc 的开发者提示在为 X86 机器构建时使用编译选项 -march=i486,尽管其他方法也能做到,但是测试显示,{zh0}的办法是将它传递给参数“CFLAGS”。为了不xx覆盖 Glibc 内部构建系统使用的 CFLAGS,使用特殊文件 configparms 将所需新选项附加到其原内容之后。由于设置了参数 -march,参数 -mtune 也会发生改变,使用 -mtune=native 将其设置为一个合理的值。 echo "CFLAGS += -march=i486 -mtune=native" > configparms 接下来,配置 Glibc 为编译做准备: ../glibc-2.8-20080929/configure --prefix=/tools \ --disable-profile --enable-add-ons \ --enable-kernel=2.6.0 --with-binutils=/tools/bin \ --without-gd --with-headers=/tools/include \ --without-selinux 配置选项的含义: --disable-profile 该设置去掉了程序性能分析相关的库文件编译。如果需要在临时工具上做程序概要分析,就省掉这个参数。 --enable-add-ons 该选项告诉 Glibc 使用 NPTL(本地 POSIX 线程库)作为其线程库。 --enable-kernel=2.6.0 告诉 Glibc 在编译库文件时支持 Linux 2.6.x 内核。 --with-binutils=/tools/bin 这个参数并不是必需的。但它们能保证在编译 Glibc 时不会用错 Binutils 程序。 --without-gd 这个参数保证不生成 memusagestat 程序,这个程序会顽固地连接到宿主系统的库文件(libgd、libpng 和 libz 等等)。 --with-headers=/tools/include 这个参数指示 Glibc 按照前面刚刚安装到 tools 目录中的内核头文件编译自己,从而xx的知道内核的特性以根据这些特性对自己进行{zj0}化编译。 --without-selinux 当从一个含有 SELinux 特性的宿主系统(如 Fedora Core 3)编译时,Glibc 将会将 SELinux 支持编译进来。由于 LFS 工具链并不包含 SELinux 支持,所以一个含有 SELinux 特性的 Glibc 将会导致许多操作失败。所以这里明确禁用它。 在此过程中可能出现下面的警告信息: configure: WARNING: *** These auxiliary programs are missing or *** incompatible versions: msgfmt *** some features will be disabled. *** Check the INSTALL file for required versions. msgfmt 程序的缺失或不兼容没有什么大问题,但是在运行测试程序时,有时可能出问题。msgfmt 是宿主系统中 Gettext 软件应提供的一部分,如果安装了 msgfmt 却不兼容,升级宿主系统的 Gettext。如果测试套件运行没有问题也可以不去管它。 编译软件包: make 该包提供了测试套件,但由于我们还没有 C++ 的编译器,现在还不能运行。 安装 Glibc 的过程会出现一个 /tools/etc/ld.so.conf 文件缺失的警告, 这没有什么危害,可以运行下面的命令xx掉: mkdir -v /tools/etc touch /tools/etc/ld.so.conf 安装: make install 不同的国家和文化,使用不同的习俗来交流。这样的习俗很多,从比较简单的时间和日期格式,到非常复杂的语言发音。GNU 程序的“internationalization”(国际化,又称“i18n”,18表示中间的18个字母)是以 locale 来实现的。 [注意] 注意 如果没有运行测试套件(正如我们推荐的),现在就没有必要安装 locales。在下一章我们会安装合适的 locales,如果想要现在安装,请参考第 6.9 节 “Glibc-2.8-20080929”里的说明。 关于这个软件包的详细资料位于第 6.9.4 节 “Glibc 的内容”。 5.8. 调整工具链 现在,安装好了 C 语言的临时库,本章中剩余章节所有要编译的工具都要链接到这些库文件上。为此,需要调整连接器和编译器的工程设计(specs)文件。 在{dy}遍编译 Binutils 结束时已经调整过的连接器,现在需要被重新命名以便可以被正确的找到和使用。首先备份原来的连接器,然后用调整过的连接器来替代,{zh1}还要创建一个指向 /tools/$(gcc -dumpmachine)/bin 中连接器副本的连接。 mv -v /tools/bin/{ld,ld-old} mv -v /tools/$(gcc -dumpmachine)/bin/{ld,ld-old} mv -v /tools/bin/{ld-new,ld} ln -sv /tools/bin/ld /tools/$(gcc -dumpmachine)/bin/ld 从现在开始,所有的程序都将链接到 /tools/lib 目录下的库文件。 下面的任务是修改 GCC 的“specs”文件,使 GCC 可以默认指向新的动态链接器。一个简单的 sed 代换就可以做到: 为了准备起见,推荐使用复制粘贴的办法来应用下面的命令。请亲眼确认下 specs 文件,保证每一处“/lib/ld-linux.so.2”都被替换成了“/tools/lib/ld-linux.so.2”: [重要] 重要 如果你的系统平台上的动态链接器名字不是 ld-linux.so.2,请将下面命令中的“ld-linux.so.2”替换为相应的动态链接器名称。如果需要,请参阅第 5.2 节 “工具链技术说明”。 gcc -dumpspecs | sed 's@/lib/ld-linux.so.2@/tools&@g' \ > `dirname $(gcc -print-libgcc-file-name)`/specs 在编译过程中,GCC 会运行 fixincludes 脚本来扫描系统头文件目录,并找出需要修正的头文件(比如包含语法错误),然后把修正后的文件放到 GCC 专属头文件目录里。因此,它可能会找出宿主系统中需要修正的头文件,并将修正后的结果放到 GCC 专属头文件目录里。由于本章的剩余部分仅需要使用当前已经安装好的 GCC 和 Glibc 的头文件,所以任何“修正后的”头文件都可以被安全的删除。并且这样做也有助于避免宿主系统中的头文件污染编译环境。运行下面的命令删除 GCC 专属头文件目录中的头文件(由于命令较长,推荐你拷贝和粘贴命令,而不是手动输入): GCC_FIXED=`dirname $(gcc -print-libgcc-file-name)`/include-fixed && find ${GCC_FIXED}/* -maxdepth 0 -xtype d -exec rm -rvf '{}' \; && rm -vf `grep -l "DO NOT EDIT THIS FILE" ${GCC_FIXED}/*` && unset GCC_FIXED [小心] 小心 现在,有必要停下来检查新工具链能够完成预期功能(编译和链接),运行下面命令完成合理的检查: echo 'main(){}' > dummy.c cc dummy.c readelf -l a.out | grep ': /tools' 如果工作一切正常,应该不会出错,{zh1}一个命令的输出应该是: [Requesting program interpreter: /tools/lib/ld-linux.so.2] 注意,/tools/lib 应该是动态链接器的前缀。 如果输出和上面的不一样,或者根本没有输出,就一定是出错了。返回前面的步骤查找问题所在,在纠正这个问题之前不要继续往下做。首先,重新做上一个检查,但用 gcc 替换 cc,如果这次输出正确了,说明链接到 cc 的符号链接有问题,返回第 5.5 节 “GCC-4.3.2 - {dy}遍”创建符号链接。下一步,确保 PATH 变量的正确,这可以通过运行 echo $PATH,验证 /tools/bin是否在输出列表的最开头。如果 PATH 变量出错,可能是因为你不是作为 lfs 用户登入,也可能是在做第 4.4 节 “设置编译环境”时出错了。另外一个原因可能是上面修正 specs 文件时出错,如果这样,重新修改 specs 文件,复制粘贴时要小心仔细。 一切正常之后,清理测试文件: rm -v dummy.c a.out [注意] 注意 下一节编译 Tcl 时为了验证工具链构建正确而做的附加检验工具。如果 Tcl 编译失败,错误出在 Binutils、GCC、或者 Glibc 的安装,而不是 Tcl 本身。 5.9. Tcl-8.5.5 Tcl 软件包包含工具命令语言(Tool Command Language)。 预计编译时间: 0.5 SBU 所需磁盘空间: 36 MB 5.9.1. Tcl 的安装 这个软件包和接下来的两个(Expect 和 DejaGNU)的安装用于支持运行 GCC 和 Binutils 的测试程序。仅仅为了测试目的安装三个软件包看起来显得多余,虽然不是必须的,但是为了最重要的工具能正常工作,这样做会更让人放心。即使现在不会运行这些测试程序,第六章中的测试也会需要这些。 准备编译 Tcl: cd unix ./configure --prefix=/tools 编译它 make 现在编译完成了,如前所述,在本章为了一个临时工具运行测试程序不是强制的。如果要测试它,运行下面命令: TZ=UTC make test 现在还不xx清楚为什么 Tcl 的测试程序在某些宿主系统上会遭遇失败。因此,如果测试失败了也不要紧,这并不是关键。参数 TZ=UTC 将时区设置为协调通用时间(UTC),也就是格林尼治时间(GMT),但仅仅在测试时。这保证了时钟测试的正确性。关于环境变量 TZ 的详细信息请参阅第七章。 安装软件包: make install 将安装的库文件设置为可写,以便后面剔除调试信息: chmod -v u+w /tools/lib/libtcl8.5.so 安装 Tcl 的头文件,安装下一个软件包(Expect)时会用到。 make install-private-headers 添加必要的符号链接: ln -sv tclsh8.5 /tools/bin/tclsh 5.9.2. Tcl 的内容 安装的程序: tclsh(链接到 tclsh8.5)和 tclsh8.5 安装的库: libtcl8.5.so 简要描述 tclsh8.5 Tcl 命令行 Shell tclsh 到 tclsh8.5 的链接 libtcl8.5.so Tcl 库 5.10. Expect-5.43.0 Expect 提供了一个与其他交互式程序提供脚本接口的工具。 预计编译时间: 0.1 SBU 所需磁盘空间: 4 MB 5.10.1. 安装 Expect 首先修正一个导致运行 GCC 测试程序失败的 bug: patch -Np1 -i ../expect-5.43.0-spawn-1.patch 接着修正由于近期 Tcl 更新产生的 bug: patch -Np1 -i ../expect-5.43.0-tcl_8.5.5_fix-1.patch 接下来,强制 Expect 配置脚本使用 /bin/stty,而不是使用可能在宿主系统中的 /usr/local/bin/stty。这保证我们的测试套件对于最终构造的工具链仍然稳健。 cp -v configure{,.orig} sed 's:/usr/local/bin:/bin:' configure.orig > configure 现在可以准备编译: ./configure --prefix=/tools --with-tcl=/tools/lib \ --with-tclinclude=/tools/include --with-x=no 配置选项的含义: --with-tcl=/tools/lib 这能确保配置脚本能找到临时系统目录下安装的 Tcl,而不是宿主系统可能安装的。 --with-tclinclude=/tools/include 这明确指出了 Tcl 内部头文件的位置。这能防止由于 configure 不能自动寻找到 Tcl 内部头文件导致的配置失败。 --with-x=no 告诉配置脚本不去搜索 Tk (Tcl 的图形界面组件)或 X Window 系统库,两者可能存在于宿主系统,但在临时环境中不存在。 编译它: make 编译完成之后,如前所述,在本章为了一个临时工具运行测试程序不是强制的。如果要测试 Expect,运行下面命令: make test 请注意,已知 Expect 的测试程序会在某些不在我们控制范围内的宿主系统下出现测试失败。因此,测试失败也并不奇怪,这不是关键所在。 安装软件包: make SCRIPTS="" install 配置选项的含义: SCRIPTS="" 这个选项防止安装 Expect 补充的一些并不需要的脚本。 |