6.10. 调节工具链

现在最终的 C 库安装好了,我们应该调节工具链使得新编译的程序会链接到这些新的库。

首先,备份 /tools 中的链接器,并且将其替换为我们在第五章中调节过的链接器。我们还要创建一个到它在 /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

下一步,修改 GCC 的 specs 文件指向新的动态链接器。简单地删除所有存在的 /tools 就可以剩下到动态链接器的正确路径。另外要使 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 'main(){}' > dummy.c
cc dummy.c -v -Wl,--verbose &> dummy.log
readelf -l a.out | grep ': /lib'

如果一切工作正常,就不应该出错,最后一条命令的输出 (允许动态链接器名称中有针对平台的差异) 应为:

[Requesting program interpreter: /lib/ld-linux.so.2]

注意 /lib 现在是我们动态链接器的前缀。

现在确保设置为使用正确的起始文件:

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

如果一切工作正常,就不应该出错,最后一条命令的输出应为:

/usr/lib/crt1.o succeeded
/usr/lib/crti.o succeeded
/usr/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'

如果一切工作正常,就不应该出错,最后一条命令的输出 (允许目标三联字串中有针对平台的差异) 应为:

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

下一步确认我们使用的是正确的 libc:

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

如果一切工作正常,就不应该出错,最后一条命令的输出 (允许 64 位宿主上有 lib64 目录) 应为:

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

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

grep found dummy.log

如果一切工作正常,就不应该出错,最后一条命令的输出 (允许动态链接器名称中有针对平台的差异、64 位宿主上有 lib64 目录) 应为:

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

如果输出不如上文所示或者根本没有输出,那么一定有某个地方严重出错了。回溯步骤,找出问题并且修正。最可能出现的原因是 specs 文件调节出错。在进行下一步之前一定要解决所有问题。

一切都正常工作之后,清理测试文件:

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