6.10. 调整工具链

现在最终的 C 运行库已经安装好了,这时就要调整工具链, 以便将新编译的任何程序都链接到新的 C 运行库。

首先,备份 /tools 中的链接器,把它替换成第 5 章准备的调整好的链接器。 我们也会把 /tools/$(uname -m)-pc-linux-gnu/bin 中对应的链接器替换成一个符号链接:

mv -v /tools/bin/{ld,ld-old}
mv -v /tools/$(uname -m)-pc-linux-gnu/bin/{ld,ld-old}
mv -v /tools/bin/{ld-new,ld}
ln -sv /tools/bin/ld /tools/$(uname -m)-pc-linux-gnu/bin/ld

下面修改 GCC 的 specs 文件,使其指向新的动态链接器。 把所有的 /tools 删除掉就会留下正确的路径。 另外,调整 specs 文件,使得 GCC 知道去哪里寻找正确的头文件和 Glibc 启动文件。一个 sed 命令即可完成以上工作:

gcc -dumpspecs | sed -e 's@/tools@@g'                   \
    -e '/\*startfile_prefix_spec:/{n;s@.*@/usr/lib/ @}' \
    -e '/\*cpp:/{n;s@$@ -isystem /usr/include@}' >      \
    `dirname $(gcc --print-libgcc-file-name)`/specs

这时最好浏览一下生成的 specs 文件,以确认确实进行了我们期望的修改。

现在的当务之急是保证调整过的工具链的基本功能(编译和链接) 能够像我们期望的那样工作。为此,进行下列完整性检查:

echo 'int main(){}' > dummy.c
cc dummy.c -v -Wl,--verbose &> dummy.log
readelf -l a.out | grep ': /lib'

上述命令不应该出现错误,最后一行命令输出的结果应该 (不同平台的动态链接器名称可能不同)是:

[Requesting program interpreter: /lib64/ld-linux-x86-64.so.2]

注意在 64 位系统上 /lib 是动态链接器的位置,但通过 /lib64 中的符号链接访问。

[注意]

译注

虽然可以把编译器查找动态链接器的位置修改到 /lib 中, 使得构建出的 LFS 系统完全不需要 /lib64 目录, 但动态链接器的位置是硬编码在 ELF 文件中的。 因此,为了运行其他机器编译出来的二进制文件 (例如 BLFS 中安装 JDK 时), 必须创建该符号链接以符合通用惯例。

[注意]

注意

在 32 位系统上,解释器是 /lib/ld-linux.so.2 。

下面确认我们的设定能够使用正确的启动文件:

grep -o '/usr/lib.*/crt[1in].*succeeded' dummy.log

以上命令应该输出:

/usr/lib/../lib/crt1.o succeeded
/usr/lib/../lib/crti.o succeeded
/usr/lib/../lib/crtn.o succeeded

确认编译器能正确查找头文件:

grep -B1 '^ /usr/include' dummy.log

该命令应当输出:

#include <...> search starts here:
 /usr/include

下一步确认新的链接器使用了正确的搜索路径:

grep 'SEARCH.*/usr/lib' dummy.log |sed 's|; |\n|g'

那些包含 '-linux-gnu' 的路径应该忽略, 除此之外,以上命令应该输出:

SEARCH_DIR("/usr/lib")
SEARCH_DIR("/lib")

之后确认我们使用了正确的 libc:

grep "/lib.*/libc.so.6 " dummy.log

以上命令应该输出:

attempt to open /lib/libc.so.6 succeeded

最后,确认 GCC 使用了正确的动态链接器:

grep found dummy.log

以上命令应该输出(不同平台的动态链接器名称可能不同):

found ld-linux-x86-64.so.2 at /lib/ld-linux-x86-64.so.2

如果输出和以上描述不符,或者根本没有输出, 那么必然有什么地方出了严重错误。检查并重新跟踪以上步骤, 找到问题的原因,并修复它。 最可能的原因是修改 specs 文件的时候出了错误。 这里出现的任何问题在继续构建前都必须解决。

在确认一切工作良好后,删除测试文件:

rm -v dummy.c a.out dummy.log