现在最终的 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