6.21.1. 安装 GCC
如果是在 x86_64 上实施构建,更改 64 位库的默认目录名为「lib」:
case $(uname -m) in
x86_64)
sed -e '/m64=/s/lib64/lib/' \
-i.orig gcc/config/i386/t-linux64
;;
esac
GCC 的文档建议在源代码目录之外一个专用的编译目录中编译 GCC:
mkdir -v build
cd build
准备编译 GCC:
SED=sed \
../configure --prefix=/usr \
--enable-languages=c,c++ \
--disable-multilib \
--disable-bootstrap \
--with-system-zlib
注意,对于其它的编程语言,现在还有一些前提条件没有准备好。可以查看 BLFS
Book 了解如何编译 GCC 支持的所有语言的指令。
新配置选项的含义:
-
SED=sed
-
设置环境变量防止访问到硬编码的 /tools/bin/sed 路径。
-
--with-system-zlib
-
这个选项告诉 GCC 链接系统安装的 Zlib 库,而不是它内部自带的库。
编译软件包:
make
重要
本章节中 GCC 的测试套件至关重要,任何情况下都不能跳过。
GCC 测试套件中一个测试集的会耗尽堆栈空间,因此运行测试之前要增加栈大小:
ulimit -s 32768
以非特权用户测试编译结果,不要因为出现错误就停下来:
chown -Rv nobody .
su nobody -s /bin/bash -c "PATH=$PATH make -k check"
要查看测试套件结果的概要,运行:
../contrib/test_summary
如果仅查看摘要,则使用管道 grep -A7
Summ
选项控制输出将输出。
结果可以和 http://www.linuxfromscratch.org/lfs/build-logs/9.0/
以及 https://gcc.gnu.org/ml/gcc-testresults/
上的相比较。
已知与 get_time 相关的六个测试失败。 这些显然与 en_HK 语言环境有关。
两个 experimental/net 的测试 lookup.cc 和 reverse.cc 已知会在 LFS chroot
环境失败因为它们需要 /etc /hosts 和 iana-etc。
两个测试 pr57193.c 和 pr90178.c 已知会失败。
一些意料之外的错误总是难以避免。GCC 开发者通常会意识到这些问题,但还没有解决。除非测试结果和上面 URL
中的相差很大,不然就可以安全继续。
安装软件包并删除不需要的目录:
make install
rm -rf /usr/lib/gcc/$(gcc -dumpmachine)/9.2.0/include-fixed/bits/
GCC 的构建目录现在属于 nobody
安装头文件(及其内容)目录的所有权不正确。将所有权更改为 root
用户和组:
chown -v -R root:root \
/usr/lib/gcc/*linux-gnu/9.2.0/include{,-fixed}
创建 FHS
因为「历史」原因而需要的符号链接。
ln -sv ../usr/bin/cpp /lib
很多软件包用命令 cc 调用 C
编译器。为了满足这些软件包,创建一个符号链接:
ln -sv gcc /usr/bin/cc
增加一个兼容符号链接启用编译程序时进行链接时间优化(Link Time Optimization,LTO):
install -v -dm755 /usr/lib/bfd-plugins
ln -sfv ../../libexec/gcc/$(gcc -dumpmachine)/9.2.0/liblto_plugin.so \
/usr/lib/bfd-plugins/
现在我们最终的工具链已经准备就绪了,再一次确认编译和链接都能像预期那样正常工作很重要。我们通过做和前面章节做过的相同的完整性检查做到这点:
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]
现在确保我们已经设置好了启动文件:
grep -o '/usr/lib.*/crt[1in].*succeeded' dummy.log
上一条命令的输出应该是:
/usr/lib/gcc/x86_64-pc-linux-gnu/9.2.0/../../../../lib/crt1.o succeeded
/usr/lib/gcc/x86_64-pc-linux-gnu/9.2.0/../../../../lib/crti.o succeeded
/usr/lib/gcc/x86_64-pc-linux-gnu/9.2.0/../../../../lib/crtn.o succeeded
取决于你机器的架构,上面的结果可能有稍微不同,差异通常是 /usr/lib/gcc
后目录的名称。这里重要的一点是 gcc 能在 /usr/lib
目录下找到所有的三个 crt*.o
文件。
确保链接器能找到正确的头文件:
grep -B4 '^ /usr/include' dummy.log
这条命令应该返回如下输出:
#include <...> search starts here:
/usr/lib/gcc/x86_64-pc-linux-gnu/9.2.0/include
/usr/local/include
/usr/lib/gcc/x86_64-pc-linux-gnu/9.2.0/include-fixed
/usr/include
同时,注意你的目标系统三段式后面的目录名称可能和上面的不同,这取决于你的架构。
接下来,确认新的链接器已经在使用正确的搜索路径:
grep 'SEARCH.*/usr/lib' dummy.log |sed 's|; |\n|g'
应该忽略指向带有 '-linux-gnu' 的路径,上条命令的输出应该是:
SEARCH_DIR("/usr/x86_64-pc-linux-gnu/lib64")
SEARCH_DIR("/usr/local/lib64")
SEARCH_DIR("/lib64")
SEARCH_DIR("/usr/lib64")
SEARCH_DIR("/usr/x86_64-pc-linux-gnu/lib")
SEARCH_DIR("/usr/local/lib")
SEARCH_DIR("/lib")
SEARCH_DIR("/usr/lib");
32 位的系统可能有一些不同的目录。例如,下面是一台 i686 机器的输出:
SEARCH_DIR("/usr/i686-pc-linux-gnu/lib32")
SEARCH_DIR("/usr/local/lib32")
SEARCH_DIR("/lib32")
SEARCH_DIR("/usr/lib32")
SEARCH_DIR("/usr/i686-pc-linux-gnu/lib")
SEARCH_DIR("/usr/local/lib")
SEARCH_DIR("/lib")
SEARCH_DIR("/usr/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
如果显示的结果不一样或者根本没有显示,那就出了大问题。检查并回溯之前的步骤,找到出错的地方并改正。最有可能的原因是参数文件的调整出了问题。在进行下一步之前所有的问题都要解决。
确保一切正常之后,清除测试文件:
rm -v dummy.c a.out dummy.log
最后,移动位置放错的文件:
mkdir -pv /usr/share/gdb/auto-load/usr/lib
mv -v /usr/lib/*gdb.py /usr/share/gdb/auto-load/usr/lib