关于此软件包的详细信息,位于第 6.14.2 节 “GCC 的内容”。
GCC 软件包包含 GNU 编译器,其中有 C 和 C++ 编译器。
用于测试 GCC 和 Binutils 的工具 — Tcl、Expect 以及 DejaGUN — 已经安装好了。现在可以重新安装
GCC 和 Binutils,将它们连接到新的 Glibc
上,并做相关的测试(如果做本章的测试)。请注意,这些测试套件严重依赖于正常运作的伪终端(PTY),这些伪终端通常是由宿主系统的
devpts
文件系统提供。因此请运行下面的小测试,检查宿主系统的
devpts
文件系统是否设置正确:
expect -c "spawn ls"
如果得到这样的提示:
The system has no more ptys.
Ask your system administrator to create more.
说明宿主系统没有设置好 PTYs,这样做 GCC 和 Binutils 的测试就没有意义了。想要解决该问题请参阅 http://www.linuxfromscratch.org//lfs/faq.html#no-ptys 获取更多信息。
正如在前面第 5.8 节 “调整工具链”里解释的,在一般情况下,GCC 会运行 fixincludes 脚本来修正可能存在问题的头文件。当 GCC-4.3.2 和 Glibc-2.8-20080929 都已经安装好的情况下,相应的头文件就不再需要修正了,也就不再需要 fixincludes 文件了。另外根据前面的说明,该脚本的运行会修正宿主系统中存在问题的头文件,并修正后安装 GCC 的专属头文件目录,这会影响编译环境。运行下面命令禁止 fixincludes 脚本运行:
cp -v gcc/Makefile.in{,.orig} sed 's@\./fixinc\.sh@-c true@' gcc/Makefile.in.orig > gcc/Makefile.in
在第 5.5 节 “GCC-4.3.2 -
第一遍”中,进行的 bootstrap 编译使用了 -fomit-frame-pointer
编译选项,而非 bootstrap
编译则默认忽略了该选项,所以需要使用下面的 sed 命令来确保在非 bootstrap 编译时也同样使用
-fomit-frame-pointer
选项,以保持编译的一致性:
cp -v gcc/Makefile.in{,.tmp} sed 's/^XCFLAGS =$/& -fomit-frame-pointer/' gcc/Makefile.in.tmp \ > gcc/Makefile.in
下面的命令将会更改 GCC 使用的默认动态连接器的位置,让其使用我们安装在 /tools
目录下的。该命令还将 /usr/include
从 GCC 的头文件搜索路径中删除。现在做这个工作而不是在安装后调整
specs 文件,这保证了在实际编译 GCC 的过程中就使用新的动态连接器。也就是编译过程中生成的所有新的二进制文件都会连接到新的
Glibc。
for file in $(find gcc/config -name linux64.h -o -name linux.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" >> $file touch $file.orig done
如果觉得上面的太长,不好理解。我们分解开来解释,首先寻找 gcc/config 目录下的所有名为 linux.h
或 linux64.h
的文件,复制这些文件并改名,在其后面添加后缀“.orig”,第一个 sed
表达式在这些文件中的每一处 “/lib/ld”、“/lib64/ld” 或 “/lib32/ld”
前面添加 “/tools”。第二个表达式替换每一个硬编码的
“/usr”。接着,我们定义一个语句,将头文件搜索路径移动到文件的最后。最后,使用
touch
来更新复制文件的时间戳。由于可能运行多次,使用 cp
-u 可以防止原来的文件被更改。
如同第一次一样,GCC 需要 GMP 和 MPFR 包,解压它们,改名并移动到所需的目录:
tar -jxf ../mpfr-2.3.2.tar.bz2 mv mpfr-2.3.2 mpfr tar -jxf ../gmp-4.2.4.tar.bz2 mv gmp-4.2.4 gmp
按照 GCC 建议的那样,再次创建一个独立的编译目录:
mkdir -v ../gcc-build cd ../gcc-build
在编译GCC之前记得,取消任何优化编译选项:
现在开始准备编译:
../gcc-4.3.2/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-bootstrap
配置选项的含义:
--enable-clocale=gnu
该选项保证在任何情况下都会为 C++ 库选择正确的 locale 模块。如果配置脚本发现安装了 de_DE locale,它能选择正确的 gnu locale 模块,但是如果没有安装 de_DE,就会选择不正确的通用 locale 模块,这可能构建与应用程序二进制接口(ABI)不兼容的 C++ 库。
--enable-threads=posix
使 C++ 异常处理能处理多线程代码。
--enable-__cxa_atexit
为本地静态和全局函数注册 C++ 析构函数时使用 __cxa_atexit
而不是 atexit
,这是为了使对析构函数的处理完全符合标准规定。这还会影响 C++ 的
ABI,从而使 C++ 共享库和 C++ 程序可以在其他 Linux 发行版中使用。
--enable-languages=c,c++
保证编译 C 和 C++ 的编译器。
--disable-libstdcxx-pch
不为 libstdc++ 构建预编译头文件(PCH),这会占用很多空间,但我们用不到它。
--disable-bootstrap
GCC 默认采用 bootstrap 方法编译自身,但是我们已经能提供一个稳健的编译器,不需要每次都 bootstrap。
编译软件包:
make
现在编译完成了,如前所述,在本章为了一个临时工具运行测试程序不是强制的。如果想运行 GCC 的测试套件,使用下列命令:
make -k check
参数 -k
用来保证 GCC
在遇到错误时不会停下来,直到全部测试完成。GCC 的测试套件非常全面,几乎肯定会出些错误。
关于特别重要的测试的出错讨论,请参考第 6.14 节 “GCC-4.3.2”。
安装 GCC:
make install
现在,有必要停下来检查新工具链能够完成预期功能(编译和链接),运行下面命令完成合理的检查:
echo 'main(){}' > dummy.c cc dummy.c readelf -l a.out | grep ': /tools'
如果工作一切正常,应该不会出错,最后一个命令的输出应该是:
[Requesting program interpreter:
/tools/lib/ld-linux.so.2]
注意,/tools/lib
应该是动态链接器的前缀。
如果输出和上面的不一样,或者根本没有输出,就一定是出错了。返回前面的步骤查找问题所在,在纠正这个问题之前不要继续往下做。首先,重新做上一个检查,但用
gcc 替换 cc,如果这次输出正确了,说明链接到 cc 的符号链接有问题,返回第 5.5 节 “GCC-4.3.2 -
第一遍”创建符号链接。下一步,确保 PATH
变量的正确,这可以通过运行 echo
$PATH,验证 /tools/bin
是否在输出列表的最开头。如果 PATH
变量出错,可能是因为你不是作为 lfs
用户登入,也可能是在做第 4.4 节
“设置编译环境”时出错了。另外一个原因可能是上面修正 specs 文件时出错,如果这样,重新修改 specs
文件,复制粘贴时要小心仔细。
一切正常之后,清理测试文件:
rm -v dummy.c a.out
关于此软件包的详细信息,位于第 6.14.2 节 “GCC 的内容”。