该软件包的更多细节在 第 6.21.2 节 “GCC 的内容” 中可以找到。
GCC 软件包包含 GNU 编译器集合,其中有 C 和 C++ 编译器。
目前 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.h
、 gcc/config/i386/linux.h
、 gcc/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 的内容” 中可以找到。