5.10. GCC-4.4.3 - 第二遍

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

预计编译时间: 9.0 SBU
所需磁盘空间: 1003 MB

5.10.1. 安装 GCC

高于4.3版的GCC 把这个编译当做一个重置的编译器, 并且禁止在被 --prefix指定的位置搜索 startfiles。因为这次不是重置的编译器,并且 /tools 目录中的startfiles 对于创建一个链接到 /tools 目录库的工作编译器很重要,所以我们使用下面的补丁, 它可以部分还原GCC的老功能:

patch -Np1 -i ../gcc-4.4.3-startfiles_fix-1.patch

在正常条件下,运行GCC的 fixincludes 脚本,是为了修复可能损坏的头文件。 因为, 现在已经安装 GCC-4.4.3 和 Glibc-2.11.1, 并且它们各自的头文件众所周知, 没必要修复, 所以, 不需要运行这个 fixincludes 脚本。 事实上, 运行这个脚本确实会污染编译环境, 因为它会把宿主系统中已修复的头文件安装到GCC专属头文件目录里。 通过执行下面的命令, 可以抑制 fixincludes 脚本的运行:

cp -v gcc/Makefile.in{,.orig}
sed 's@\./fixinc\.sh@-c true@' gcc/Makefile.in.orig > gcc/Makefile.in

对于x86 系统,GCC 的自举编译,使用 -fomit-frame-pointer编译器标志。 非自举(Non-bootstrap)编译, 默认忽略这些标志, 如果是可自举的, 目标就应该是产生一个完全相同的编译器。 应用下面的 sed命令, 来强行使编译过程使用这个标志:

cp -v gcc/Makefile.in{,.tmp}
sed 's/^T_CFLAGS =$/& -fomit-frame-pointer/' gcc/Makefile.in.tmp \
  > gcc/Makefile.in

下面的命令会更改GCC的默认动态链接器的位置,来使用已安装在 /tools 目录下的链接器, 它也会从 GCC的 include 搜索目录删除 /usr/include。 现在这样做, 而不是等安装以后, 在调整specs文件, 是为了确保在GCC真实的编译过程中, 使用新的动态链接器。 也就是说, 在编译过程中创建的所有二进制文件,都会链接到新的 Glibc文件。执行:

for file in \
 $(find gcc/config -name linux64.h -o -name linux.h -o -name sysv4.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_INCLUDE_DIR
#define STANDARD_INCLUDE_DIR 0
#define STANDARD_STARTFILE_PREFIX_1 ""
#define STANDARD_STARTFILE_PREFIX_2 ""' >> $file
  touch $file.orig
done

在上述情况下,似乎难以适从,让我们分解一下。首先,我们找到 gcc/config目录下的所有文件, 它们命名为linux.h, linux64.hsysv4.h. 我们把找到的每个文件都拷贝成同名的,加“.orig” 后缀的文件。然后,在第一个表达式的“/lib/ld”, “/lib64/ld” 或 “/lib32/ld”前添加 “/tools” 。 第二个sed 表达式,取消 “/usr” 的硬编码实例。 接着,我们添加 define 语句, 它用来改变 include 搜索路径和默认的启动文件。最后,我们使用 touch 来更新拷贝文件上的时间戳。 cp -u 一起使用,可以防止如果这个命令被无意中执行两次, 会改变原始文件。

对于 x86_64平台,不为 GCC 设置 multilib 的 spec 文件, 这样可以确保它不会链接到宿主系统的库文件:

case $(uname -m) in
  x86_64)
    for file in $(find gcc/config -name t-linux64) ; do \
      cp -v $file{,.orig}
      sed '/MULTILIB_OSDIRNAMES/d' $file.orig > $file
    done
  ;;
esac

正如第一遍安装一样,GCC需要 GMP 和 MPFR 软件包。 展开这两个tar包, 并将其改成所需的目录名:

tar -jxf ../mpfr-2.4.2.tar.bz2
mv -v mpfr-2.4.2 mpfr
tar -jxf ../gmp-5.0.0.tar.bz2
mv -v gmp-5.0.0 gmp

再次创建专用目录:

mkdir -v ../gcc-build
cd ../gcc-build

在开始编译GCC以前,记住 unset 任何优化相关的环境变量。

现在为编译 GCC 做准备:

CC="$LFS_TGT-gcc -B/tools/lib/" \
    AR=$LFS_TGT-ar RANLIB=$LFS_TGT-ranlib \
    ../gcc-4.4.3/configure --prefix=/tools \
    --with-local-prefix=/tools --enable-clocale=gnu \
    --enable-shared --enable-threads=posix \
    --enable-__cxa_atexit --enable-languages=c,c++ \
    --disable-libstdcxx-pch --disable-multilib \
    --disable-bootstrap

新配置参数的含义:

--enable-clocale=gnu

本参数确保C++库在任何情况下都使用正确的 locale 模块。如果配置脚本查找到安装的 de_DE locale ,它就会使用正确的 gnu locale 模块。然而,如果没有安装 de_DE locale, 就有可能创建出应用程序二进制接口(ABI)不兼容的C++库文件, 这是因为选择了错误的通用 (generic) locale 模块。

--enable-threads=posix

使 C++ 异常能处理多线程代码。

--enable-__cxa_atexit

本参数允许用 __cxa_atexit 代替 atexit 来登记 C++ 对象的本地静态和全局析构函数, 这是为了完全符合 标准对析构函数的处理规定。 它还会影响到 C++ ABI ,因此生成的 C++ 共享库和 C++程序在其他的 Linux 发行版上也能使用。

--enable-languages=c,c++

本参数确保编译 C 和 C++ 语言的编译器。

--disable-libstdcxx-pch

不为 libstdc++ 编译预编译头(PCH),它占用了很大空间,并且我们用不到它。

--disable-bootstrap

对于本地编译GCC,默认是进行"bootstrap" 编译。这不仅仅是编译GCC,而且要编译好几次。它用第一次编译的程序再次编译它自己,然后再第三次编译。 第二次和第三次迭代比较来确保重新生成完美的自己。 这也暗示编译正确。 然而, LFS系统创建方法应该提供一个可信赖的 无需每次引导编译器。

编译这个软件包:

make

安装这个软件包:

make install

作为画龙点睛,创建一个符号链接。很多程序和脚本运行 cc 而不是 gcc, 这可以保持程序的通用性, 并可以用在各种UNIX系统上。UNIx系统并不都安装GNU C编译器。 运行 cc 让系统管理员自由决定要安装哪一个C编译器:

ln -vs gcc /tools/bin/cc
[Caution]

小心

现在,需要停下来确认新工具链的基本功能(编译和连接)是否按预期工作, 运行下面的命令做一个简单的合理性检查:

echo 'main(){}' > dummy.c
cc dummy.c
readelf -l a.out | grep ': /tools'

如果一切正常,应该不会出错,而且最后一个命令的结果应当是:

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

注意,动态链接器的前缀是 /tools/lib, 或对于64位机器是 /tools/lib64

如果输出和上面写的不一样,或者根本没有输出,那就有问题了。调查和追溯这些步骤 , 以便找出哪里出了问题,并改正它。 继续操作以前,必须解决问题。首先,使用 gcc 而不是 cc,再仔细检查一遍。如果这样正常,说明 /tools/bin/cc 符号链接不见了。安装上述符号链接。然后,确保路径正确,者可以通过运行 echo $PATH检查,并保证 /tools/bin 在表头。 如果路径不正确,可能意味着你不是用 lfs用户登录的,或者前面的 Section 4.4, “设置环境变量.” 设置有错误。

一旦所有都正确,清空测试文件:

rm -v dummy.c a.out

这个软件包的详细内容位于 Section 6.16.2, “Contents of GCC.”