这个软件包的详细内容位于 Section 6.16.2, “Contents of GCC.”
GCC 软件包包含 GNU 编译器集合,包括 C 和 C++ 编译器。
高于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.h
或 sysv4.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
现在,需要停下来确认新工具链的基本功能(编译和连接)是否按预期工作, 运行下面的命令做一个简单的合理性检查:
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.”