5.5. GCC-8.2.0 - 第一遍

GCC 软件包包含 GNU 编译器集合,其中有 C 和 C++ 编译器。

估计编译时间: 14.3 SBU
需要硬盘空间: 2.2 GB

5.5.1. 安装交叉工具链中的 GCC

目前 GCC 依赖于 GMP、MPFR 和 MPC 这三个包。 由于宿主发行版未必包含它们,我们将它们和 GCC 一同构建。 将它们都解压到 GCC 源码目录中,并重命名解压出的目录, 这样 GCC 构建过程就能自动使用它们:

[注意]

注意

对于本章内容有一些很常见的误解。该软件包的构建过程就像之前 (软件包构建说明) 解释的那样, 首先解压 GCC 压缩包,切换到解压出的目录中,再执行下面的命令。

tar -xf ../mpfr-4.0.1.tar.xz
mv -v mpfr-4.0.1 mpfr
tar -xf ../gmp-6.1.2.tar.xz
mv -v gmp-6.1.2 gmp
tar -xf ../mpc-1.1.0.tar.gz
mv -v mpc-1.1.0 mpc

下面的命令修改 GCC 的默认动态链接器位置,以使用 /tools 中的动态链接器。 同时,从 GCC 的头文件搜索路径中删除 /usr/include 。执行:

for file in gcc/config/{linux,i386/linux{,64}}.h
do
  cp -uv $file{,.orig}
  sed -e 's@/lib\(64\)\?\(32\)\?/ld@/tools&@g' \
      -e 's@/usr@/tools@g' $file.orig > $file
  echo '
#undef STANDARD_STARTFILE_PREFIX_1
#undef STANDARD_STARTFILE_PREFIX_2
#define STANDARD_STARTFILE_PREFIX_1 "/tools/lib/"
#define STANDARD_STARTFILE_PREFIX_2 ""' >> $file
  touch $file.orig
done

如果上面的命令看上去难以理解,把它分开来看。首先我们复制 gcc/config/linux.hgcc/config/i386/linux.hgcc/config/i386/linux64.h, 将它们备份为名称是原文件名加上 .orig 后缀的文件。 然后第一个 sed 表达式将所有 /lib/ld/lib64/ld 或者 /lib32/ld 之前都加上 /tools,第二个将硬编码的 /usr 替换掉。然后,我们在文件末尾增加自己的宏定义, 修改默认的启动文件 (startfile) 前缀。注意,在 /tools/lib/ 中,最后的 / 是必要的。 最后,使用 touch 命令更新被复制的文件的时间戳。 这与 cp -u 命令结合起来, 防止我们不小心把命令输入两次,从而对文件造成非预期的修改。

对于 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:

../configure                                       \
    --target=$LFS_TGT                              \
    --prefix=/tools                                \
    --with-glibc-version=2.11                      \
    --with-sysroot=$LFS                            \
    --with-newlib                                  \
    --without-headers                              \
    --with-local-prefix=/tools                     \
    --with-native-system-header-dir=/tools/include \
    --disable-nls                                  \
    --disable-shared                               \
    --disable-multilib                             \
    --disable-decimal-float                        \
    --disable-threads                              \
    --disable-libatomic                            \
    --disable-libgomp                              \
    --disable-libmpx                               \
    --disable-libquadmath                          \
    --disable-libssp                               \
    --disable-libvtv                               \
    --disable-libstdcxx                            \
    --enable-languages=c,c++

配置选项的含义:

--with-newlib

由于现在没有可用的 C 运行库,使用该选项保证构建 libgcc 时 inhibit_libc 常量被定义, 以防止编译任何需要 libc 支持的代码。

[注意]

译注

这个选项对于嵌入式系统工程师来说显得很奇怪, 因为 LFS 和嵌入式系统中常用的 C 运行库 newlib 毫无关系。 参见译者和 GCC 开发者的讨论: https://gcc.gnu.org/ml/gcc-help/2017-04/msg00029.html

--without-headers

在创建完整的交叉编译器时, GCC 需要与目标系统兼容的标准头文件。 由于我们的特殊目的,这些头文件并不必要。 这个开关防止 GCC 查找它们。

--with-local-prefix=/tools

本地前缀是 GCC 在系统中寻找本地安装的包含文件的位置, 它的默认值是 /usr/local 。 将它设置为 /tools, 从而将宿主系统的 /usr/local 排除在 GCC 搜索路径外。

--with-native-system-header-dir=/tools/include

默认情况下,GCC 在 /usr/include 中搜索系统头文件。由于我们使用了 sysroot 开关, 它会被改写成 $LFS/usr/include。 然而,在之后的两节中,我们会把头文件安装在 $LFS/tools/include, 本开关保证 GCC 能够正确地找到它们。 在第二遍编译 GCC 时,这个开关保证不会查找宿主系统的头文件。

--disable-shared

这个开关强制 GCC 静态链接它的内部库, 以防止宿主系统可能带来的问题。

--disable-decimal-float, --disable-threads, --disable-libatomic, --disable-libgomp, --disable-libmpx, --disable-libquadmath, --disable-libssp, --disable-libvtv, --disable-libstdcxx

这些开关禁用对于十进制浮点数、线程、libatomic、libgomp、 libmpx、libquadmath、libssp、libvtv 和 C++ 标准库的支持。 在构建交叉编译器时它们的编译会失败,而且在交叉编译临时 libc 时并不需要它们。

--disable-multilib

在 x86_64 平台上,LFS 目前不支持 multilib 配置。 这个开关对于 x86 来说可有可无。

--enable-languages=c,c++

这个选项保证只构建 C 和 C++ 编译器。目前只需要这两个语言。

执行以下命令编译 GCC:

make

现在我们编译完成了 GCC。此时,通常来说应该执行测试套件。 然而正如前文所述,测试套件框架还没有就位, 而且第一遍编译的 GCC 程序很快就会被替换,运行测试套件的收益极小。

安装该软件包:

make install

该软件包的更多细节在 第 6.21.2 节 “GCC 的内容” 中可以找到。