💎一站式轻松地调用各大LLM模型接口,支持GPT4、智谱、星火、月之暗面及文生图 广告
# 6.12\. GCC-4.0.3 GCC 软件包包含 GNU 编译器,其中有 C 和 C++ 编译器。 **预计编译时间:** 22 SBU (含测试套件)**所需磁盘空间:** 566 MB (含测试套件) ## 6.12.1\. 安装 GCC 使用一个 `sed` 命令来禁止 GCC 安装它自己的 `libiberty.a` 。我们将使用 Binutils 附带的 `libiberty.a` 来代替: ``` sed -i 's/install_to_$(INSTALL_DEST) //' libiberty/Makefile.in ``` 在[节 5.4, "GCC-4.0.3 - 第一遍"](../chapter05/gcc-pass1.html "5.4\. GCC-4.0.3 - 第一遍") 中应用的 bootstrap 编译中,编译器会有 `-fomit-frame-pointer` 的标志。非bootstrap编译默认是忽略这个标志的,可以应用下面的`sed` 命令来确保编译的可靠性。 ``` sed -i 's/^XCFLAGS =$/& -fomit-frame-pointer/' gcc/Makefile.in ``` `fixincludes` 脚本偶尔会因为修改系统的头文件而出错。因为GCC-4.0.3 和 Glibc-2.3.6 是不需要修改的,运行下面的命令可以避免 `fixincludes` 脚本运行: ``` sed -i 's@\./fixinc\.sh@-c true@' gcc/Makefile.in ``` GCC 中提供了一个 `gccbug` 脚本,会在编译时侦测 mktemp 是否存在,并且在测试中加强代码。这将会导致脚本使用一些不算很随机的名字来命名临时文件。因为我们后面会安装 mktemp ,这里我们就模仿它的存在: ``` sed -i 's/@have_mktemp_command@/yes/' gcc/gccbug.in ``` GCC 的安装指南推荐用一个新建的目录来编译它,而不是在源码目录中: ``` mkdir -v ../gcc-build cd ../gcc-build ``` 为编译 GCC 做准备: ``` ../gcc-4.0.3/configure --prefix=/usr \ --libexecdir=/usr/lib --enable-shared \ --enable-threads=posix --enable-__cxa_atexit \ --enable-clocale=gnu --enable-languages=c,c++ ``` 编译软件包: ``` make ``` ### 重要 本节的GCC测试套件很重要。在任何情况下都不要省略这一步。 运行测试套件,但遇到错误不停止(你还记得那些老是出错的测试吧): ``` make -k check ``` 要查看测试单元的测试结果,可以运行: ``` ../gcc-4.0.3/contrib/test_summary ``` 如果只想看概要,可以把输出通过管道传递给 **`grep -A7 Summ`** 。 结果可以跟 [_http://www.linuxfromscratch.org/lfs/build-logs/6.2/_](http://www.linuxfromscratch.org/lfs/build-logs/6.2/) 的进行比较。 一些预想不到的错误总是无法避免的。虽然GCC的开发者经常留意这些问题,但是有些还是没有得到解决。通常,`libmudflap` 测试尤其被认为是有问题的(这是一个bug,参见[_http://gcc.gnu.org/bugzilla/show_bug.cgi?id=20003_](http://gcc.gnu.org/bugzilla/show_bug.cgi?id=20003))。 除非测试结果给上面URL的有很多不同,一般是可以安全继续的。 安装软件包: ``` make install ``` 有的软件包希望 C PreProcessor(预处理器)安装在 `/lib` 目录下,为了满足它们的要求,我们创建如下符号链接: ``` ln -sv ../usr/bin/cpp /lib ``` 许多软件包使用 `cc` 作为 C 编译器的名字,为了满足它们的要求,创建如下符号链接: ``` ln -sv gcc /usr/bin/cc ``` 现在,我们的最终工具链已经形成了,我们需要做的就是确保编译、链接按照我们希望的完成。我们可以通过本章前面的简册方法来实现: ``` echo 'main(){}' > dummy.c cc dummy.c -Wl,--verbose &> dummy.log readelf -l a.out | grep ': /lib' ``` 如果所有的都工作正常,就不会有错误,并且命令的输出应该是(允许不同平台的动态链接器的名称不同): ``` [Requesting program interpreter: /lib/ld-linux.so.2] ``` 现在确保我们使用正确的 startfiles: ``` grep -o '/usr/lib.*/crt[1in].* .*' dummy.log ``` 如果所有的都工作正常,就不会有错误,并且命令的输出应该是: ``` /usr/lib/gcc/i686-pc-linux-gnu/4.0.3/../../../crt1.o succeeded /usr/lib/gcc/i686-pc-linux-gnu/4.0.3/../../../crti.o succeeded /usr/lib/gcc/i686-pc-linux-gnu/4.0.3/../../../crtn.o succeeded ``` 接下来,确认新的链接器被应用到了正确的搜索路径中: ``` grep 'SEARCH.*/usr/lib' dummy.log |sed 's|; |\n|g' ``` 如果所有的都工作正常,就不会有错误,并且命令的输出应该是: ``` 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.so.2 at /lib/ld-linux.so.2 ``` 如果输出不是像上面那样或者根本没有输出,那么就有大问题了。返回并检查前面的操作,找出问题,并改正过来。最有可能的原因是上面修正 specs 文件时出错。任何一个问题都需要在继续之前解决掉。 一旦工具都工作正常,清理测试文件: ``` rm -v dummy.c a.out dummy.log ``` ## 6.12.2\. GCC 的内容 **安装的程序:** c++, cc(→gcc), cpp, g++, gcc, gccbug, gcov**安装的库:** libgcc.a, libgcc_eh.a, libgcc_s.so, libstdc++.{a,so}, libsupc++.a ### 简要描述 | | | | --- | --- | | `cc` | C 编译器 | | `cpp` | C 预处理器。编译器用它来将 #include 和 #define 这类声明在源文件中展开。 | | `c++` | C++ 编译器 | | `g++` | C++ 编译器 | | `gcc` | C 编译器 | | `gccbug` | 一个shell脚本,帮助创建有价值的 bug 报告。 | | `gcov` | 覆盖测试工具,用来分析在程序的哪里做优化的效果最好。 | | `libgcc` | `gcc` 的运行时库 | | `libstdc++` | 准 C++ 库,包含许多常用的函数。 | | `libsupc++` | 为 C++ 语言提供支持的库函数。 |