6.21. GCC-8.2.0

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

大致构建用时: 92 SBU (with tests)
所需磁盘空间: 3.9 GB

6.21.1. 安装 GCC

如果是在 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 将被安装在这:

rm -f /usr/lib/gcc

GCC 的文档建议在源代码目录之外一个专用的编译目录中编译 GCC:

mkdir -v build
cd       build

准备编译 GCC:

SED=sed                               \
../configure --prefix=/usr            \
             --enable-languages=c,c++ \
             --disable-multilib       \
             --disable-bootstrap      \
             --disable-libmpx         \
             --with-system-zlib

注意,对于其它的编程语言,现在还有一些前提条件没有准备好。可以查看 BLFS Book 了解如何编译 GCC 支持的所有语言的指令。

新配置选项的含义:

SED=sed

设置环境变量防止访问到硬编码的 /tools/bin/sed 路径。

--disable-libmpx

这个选项告知 GCC 不要编译 mpx (Memory Protection Extensions:内存保护扩展)。此特性在一些处理器上存在问题,已经在下一个版本的 GCC 中移除。

--with-system-zlib

这个选项告诉 GCC 链接系统安装的 Zlib 库,而不是它内部自带的库。

编译软件包:

make
[Important]

Important

本章节中 GCC 的测试套件至关重要,任何情况下都不能跳过。

GCC 测试套件中一个测试集的会耗尽堆栈空间,因此运行测试之前要增加栈大小:

ulimit -s 32768

删除已知会导致问题的测试:

rm ../gcc/testsuite/g++.dg/pr83239.C

以非特权用户测试编译结果,不要因为出现错误就停下来:

chown -Rv nobody . 
su nobody -s /bin/bash -c "PATH=$PATH make -k check"

要查看测试套件结果的概要,运行:

../contrib/test_summary

如果仅查看摘要,则使用管道 grep -A7 Summ 选项控制输出将输出:

../contrib/test_summary | grep -A7 Summ

结果可以和 http://www.linuxfromscratch.org/lfs/build-logs/8.4/ 以及 http://gcc.gnu.org/ml/gcc-testresults/ 上的相比较。

一些意料之外的错误总是难以避免。GCC 开发者通常会意识到这些问题,但还没有解决。除非测试结果和上面 URL 中的相差很大,不然就可以安全继续。

[Note]

Note

在某些内核配置和 AMD 处理器组合的时候,肯能会在 gcc.target/i386/mpx 测试(旨在测试最新英特尔处理器上的 MPX 选项)中出现 1100 个失败。AMD 处理器的话可以安心的忽略这些。

安装软件包:

make install

创建 FHS 因为「历史」原因而需要的软链接。

ln -sv ../usr/bin/cpp /lib

很多软件包用命令 cc 调用 C 编译器。为了满足这些软件包,创建一个符号链接:

ln -sv gcc /usr/bin/cc

增加一个兼容符号链接启用编译程序时进行链接时间优化(Link Time Optimization,LTO):

install -v -dm755 /usr/lib/bfd-plugins
ln -sfv ../../libexec/gcc/$(gcc -dumpmachine)/8.2.0/liblto_plugin.so \
        /usr/lib/bfd-plugins/

现在我们最终的工具链已经准备就绪了,再一次确认编译和链接都能像预期那样正常工作很重要。我们通过做和前面章节做过的相同的完整性检查做到这点:

echo 'int main(){}' > dummy.c
cc dummy.c -v -Wl,--verbose &> dummy.log
readelf -l a.out | grep ': /lib'

如果没有任何错误,上条命令的输出应该是(不同的平台上的动态链接器可能名字不同):

[Requesting program interpreter: /lib64/ld-linux-x86-64.so.2]

现在确保我们已经设置好了启动文件:

grep -o '/usr/lib.*/crt[1in].*succeeded' dummy.log

上一条命令的输出应该是:

/usr/lib/gcc/x86_64-pc-linux-gnu/8.2.0/../../../../lib/crt1.o succeeded
/usr/lib/gcc/x86_64-pc-linux-gnu/8.2.0/../../../../lib/crti.o succeeded
/usr/lib/gcc/x86_64-pc-linux-gnu/8.2.0/../../../../lib/crtn.o succeeded

取决于你机器的架构,上面的结果可能有稍微不同,差异通常是 /usr/lib/gcc 后目录的名称。这里重要的一点是 gcc 能在 /usr/lib 目录下找到所有的三个 crt*.o 文件。

确保链接器能找到正确的头文件:

grep -B4 '^ /usr/include' dummy.log

这条命令应该返回如下输出:

#include <...> search starts here:
 /usr/lib/gcc/x86_64-pc-linux-gnu/8.2.0/include
 /usr/local/include
 /usr/lib/gcc/x86_64-pc-linux-gnu/8.2.0/include-fixed
 /usr/include

同时,注意你的目标系统三段式后面的目录名称可能和上面的不同,这取决于你的架构。

接下来,确认新的链接器已经在使用正确的搜索路径:

grep 'SEARCH.*/usr/lib' dummy.log |sed 's|; |\n|g'

应该忽略指向带有 '-linux-gnu' 的路径,上条命令的输出应该是:

SEARCH_DIR("/usr/x86_64-pc-linux-gnu/lib64")
SEARCH_DIR("/usr/local/lib64")
SEARCH_DIR("/lib64")
SEARCH_DIR("/usr/lib64")
SEARCH_DIR("/usr/x86_64-pc-linux-gnu/lib")
SEARCH_DIR("/usr/local/lib")
SEARCH_DIR("/lib")
SEARCH_DIR("/usr/lib");

32 位的系统可能有一些不同的目录。例如,下面是一台 i686 机器的输出:

SEARCH_DIR("/usr/i686-pc-linux-gnu/lib32")
SEARCH_DIR("/usr/local/lib32")
SEARCH_DIR("/lib32")
SEARCH_DIR("/usr/lib32")
SEARCH_DIR("/usr/i686-pc-linux-gnu/lib")
SEARCH_DIR("/usr/local/lib")
SEARCH_DIR("/lib")
SEARCH_DIR("/usr/lib");

然后我们要确定我们使用的是正确的 libc:

grep "/lib.*/libc.so.6 " dummy.log

上条命令的输出应该为:

attempt to open /lib/libc.so.6 succeeded

最后,确保 GCC 使用的是正确的动态链接器:

grep found dummy.log

上条命令的结果应该是(不同的平台上链接器名字可以不同):

found ld-linux-x86-64.so.2 at /lib/ld-linux-x86-64.so.2

如果显示的结果不一样或者根本没有显示,那就出了大问题。检查并回溯之前的步骤,找到出错的地方并改正。最有可能的原因是参数文件的调整出了问题。在进行下一步之前所有的问题都要解决。

确保一切正常之后,清除测试文件:

rm -v dummy.c a.out dummy.log

最后,移动位置放错的文件:

mkdir -pv /usr/share/gdb/auto-load/usr/lib
mv -v /usr/lib/*gdb.py /usr/share/gdb/auto-load/usr/lib

6.21.2. GCC 软件包内容

安装的程序: c++, cc (链接到 gcc), cpp, g++, gcc, gcc-ar, gcc-nm, gcc-ranlib, 和 gcov
安装的库: libasan.{a,so}, libatomic.{a,so}, libgcc.a, libgcc_eh.a, libgcc_s.so, libgcov.a, libgomp.{a,so}, libiberty.a, libitm.{a,so}, liblto_plugin.so, libquadmath.{a,so}, libssp.{a,so}, libssp_nonshared.a, libstdc++.{a,so}, libsupc++.a, 和 libtsan.{a,so}
安装目录: /usr/include/c++, /usr/lib/gcc, /usr/libexec/gcc, 和 /usr/share/gcc-8.2.0

简要介绍

c++

C++ 编译器

cc

C 编译器

cpp

C 预处理器;编译器用来扩展源文件中 #include、#define 以及类似语句

g++

C++ 编译器

gcc

C 编译器

gcc-ar

增加插件到命令行的 ar 的封装。这个程序只用于添加 "链接时间优化",在使用默认编译选项时不起作用

gcc-nm

增加插件到命令行的 nm 的封装。这个程序只用于添加 "链接时间优化",在使用默认编译选项时不起作用

gcc-ranlib

增加插件到命令行的 ranlib 的封装。这个程序只用于添加 "链接时间优化",在使用默认编译选项时不起作用

gcov

一个覆盖测试工具;用于分析程序以决定在哪里进行优化有最大的效果

libasan

Address Sanitizer(地址消毒剂)运行时库。

libgcc

包含用于 gcc 的运行时支持

libgcov

当指示 GCC 启用分析时该库会被链接到程序中

libgomp

用于 C/C++、Fortran 语言的多平台共享内存并行编程的 OpenMP API 的 GNU 实现

libiberty

包含多种 GNU 程序所使用的例程,包括 getopt, obstack, strerror, strtol, 和 strtoul

liblto_plugin

GCC 的链接时间优化(LTO)插件,允许 GCC 跨编译单元进行优化

libquadmath

GCC 四精度数学库 API

libssp

包含支持 GCC 堆栈溢出保护功能的例程

libstdc++

标准 C++ 库

libsupc++

为 C++ 编程语言提供支持例程

libtsan

Thread Sanitizer(数据速率检测工具) 运行时库