资讯动态

GCC 9.5.0源码编译全指南:从依赖准备到版本切换的避坑手册

发布时间:2026/10/13 13:49:54 来源:尧图企业网站定制
简介GCC 9.5.0 官方源码压缩包面向需要从底层构建、定制或二次开发编译器的开发者、系统管理员以及系统学习编译原理的计算机专业学生。该资源采用 tar.gz 打包方式压缩包整体大小约 122.2MB根目录下仅含 gcc-9.5.0 单一主目录文件总数暂无明确统计属于未经第三方改动的纯净源码发行版解压后可通过 configure、make、make install 三阶段完成从源码到可执行编译器的完整构建。目前已有 170 人学习下载。深入阅读这份源码不仅可以理解 GCC 前端对 C/C/Fortran 等语言语法与语义的分析过程还能观察中端各类优化遍pass的执行逻辑以及后端针对不同指令集生成汇编的实现细节同时可对比 gcc 与 g 在调用编译驱动时对 C/C 标准、链接库和头文件路径的差异化处理。对于需要构建交叉编译器、定制本地优化选项或希望参与开源工具链贡献的读者这份源码包提供了权威、完整的起点也是编译原理课程实验与生产环境二次开发的有力支撑。1. 拿到 gcc-9.5.0.tar.gz 之后真正的麻烦才刚开始gcc-9.5.0.tar.gz这个文件名看着简单但它不是一个解压就能用的二进制包而是 GNU 编译器套件 9.5.0 版本的完整源码包。你从网上下载它多半是遇到了发行版自带的 GCC 版本太老、内核模块编不过、或者某个项目明确要求 GCC 9.x 系列的环境。尤其在很多国产化系统比如麒麟和离线服务器上包管理器里的 GCC 版本往往停留在 4.8 或 7.x这时候手动编译一个 GCC 9.5.0 就成了绕不开的路。但源码编译 GCC 和apt install gcc完全是两个量级的操作你需要先配齐依赖库、选对 configure 参数、忍受半小时以上的编译时间还要在装完后处理明明装了新版本gcc -v却还是旧版这个经典玄学。这篇文章会把从拿到这个 tar.gz 到让系统真正用上 GCC 9.5.0 的每一步讲清楚包括参数怎么设、失败了看哪里、以及那些让你翻车到怀疑人生的坑。2. 编译 GCC 之前的环境准备依赖、磁盘和这一步为何劝退很多人2.1 三条硬性依赖gmp、mpfr、mpc 和它们缺了会怎样GCC 源码编译有三个躲不掉的依赖库GMP大数运算、MPFR浮点精度、MPC复数运算。这三个库服务于 GCC 自身的优化和代码生成逻辑缺一个configure 阶段就会直接报错退出。常见的报错是configure: error: cannot find gmp.h或者mpfr.h不存在很多新手在这里就卡住了以为是自己下载的 GCC 源码包有问题其实只是依赖没装。一个容易忽略的细节是这三个库只依赖头文件和静态库也就是说你需要的是gmp-devel、mpfr-devel、mpc-devel这类开发包而不是单纯的运行库。在 Ubuntu 和麒麟系系统上包名分别是libgmp-dev、libmpfr-dev、libmpc-dev。如果是在 CentOS 或 RHEL 系则对应gmp-devel、mpfr-devel、libmpc-devel注意 CentOS 上 mpc 的包名不是mpc-devel容易在搜索时被误导。还有一条隐藏依赖GCC 编译还需要gcc本身。如果你当前的系统里连一个可用的 C 编译器都没有那就是经典的鸡生蛋问题。最常见做法是先用包管理器装一个旧版 GCC 作为引导编译器再用它来编译 GCC 9.5.0。某些精简容器镜像里连make都没有需要一并补齐。2.2 磁盘、内存与时间预算GCC 源码编译不是跑个脚本那么简单很多人对源码编译的耗时和资源占用没有概念结果在只有 2GB 内存的云服务器上直接开编编到一半就被 OOM killer 杀掉。GCC 9.5.0 完整编译的磁盘占用大约在 5GB 到 8GB编译产物加上临时文件内存建议至少 4GB否则并行编译时很容易出问题。比较稳的组合是内存 4GB、磁盘剩余 10GB 以上、单核 CPU 的情况下预留 40 到 60 分钟。时间这东西玄学成分很大。同样是 9.5.0只编 C 和 C 编译器比全部语言快很多CPU 强不强也直接决定编译时间。我见过用 8 核机器并行编译 12 分钟跑完的也见过单核小机器编了一个半小时还卡在最后阶段的。如果你心里没底编译前用df -h和free -h各看一眼心里大概有个数就行。这些年踩过的血泪经验是不要在磁盘剩余不足 2GB 的机器上尝试编译 GCC。编译到中途磁盘写满的表现不是立刻报错而是某个临时文件写入失败后产生一连串莫名其妙的报错排查起来非常吃力最后只能删掉整个 build 目录重来。2.3 用系统包管理器补齐依赖Ubuntu 与麒麟系的一行命令在 Ubuntu 和基于 Ubuntu 的麒麟系统上准备依赖可以用一条命令完成。麒麟系统无论是银河麒麟还是中标麒麟的桌面版通常基于 Ubuntu 或 Debian 体系包管理器是 apt# 更新索引并安装编译 GCC 所需的全部依赖 sudo apt update sudo apt install -y build-essential make gcc g gmp-dev libmpfr-dev libmpc-dev注意这里我写的是gmp-dev但 Ubuntu 20.04 及之后的实际包名是libgmp-dev。麒麟系统的软件源版本不同包名可能有差异如果遇到Unable to locate package先用apt search gmp搜一下实际的名字。build-essential会附带安装 make、默认版本的 gcc 和 g这正好满足我们前面说的需要一个引导编译器的要求。如果是在 CentOS/RHEL 系的离线环境没有外网镜像那就得用 RPM 包手动装依赖。把gmp-devel、mpfr-devel、libmpc-devel的 RPM 文件准备好用rpm -ivh按依赖顺序安装。这个过程偶尔会遇到某个依赖又依赖别的东西的情况属于离线编译的常态逐个补就是。还有个经常被忽略的点确认make版本不要太老。GCC 9.5.0 的构建系统要求 make 3.81 以上绝大多数现代发行版都能满足但有些老旧的 CentOS 6 只有 make 3.81恰好卡在最低线上可能出现一些诡异的构建错误。3. 从 tar.gz 到 gcc 可执行文件configure、make、make install 全流程3.1 解压与目录规划不要在源码目录里直接编译建 build 目录的理由拿到gcc-9.5.0.tar.gz之后第一步当然是解压。但解压之后怎么做不同人的习惯差异很大。官方文档推荐的、我也一直用的做法是另建一个 build 目录在 build 目录里执行 configure 和 make源码目录保持干净。这样做的理由很实际GCC 支持在同一份源码上做多套配置比如一套只编 C 编译器、另一套带 Fortran、还有一套开特定优化选项。每次重新编译时只需要清空 build 目录源码不会被残留的中间文件污染。如果直接在源码目录里编译出错了想重来要么make clean不一定清理干净要么就得重新解压一份源码很被动。# 解压源码包 tar -xf gcc-9.5.0.tar.gz # 进入源码目录创建 build 子目录 cd gcc-9.5.0 mkdir build cd build # 确认当前目录 pwd执行完pwd后你应该处于gcc-9.5.0/build目录下。后面所有 configure 和 make 操作都在这里完成。一个小建议解压后顺手看一眼gcc-9.5.0目录里有没有README和INSTALL文件INSTALL文件里会写明这个版本的最低依赖版本要求比如 GMP 要求 4.3.2 以上、MPFR 要求 2.4.2 以上。多数发行版的开发包都能满足但如果你用的是比较老的系统还是核对一下比较稳妥。3.2 configure 阶段--prefix、--enable-languages、--disable-multilib 怎么配configure 是整个过程中最需要花心思的一步。参数配得好后面编译顺利配不好要么编译失败要么装完发现功能缺这缺那。我一般用的配置是一套经过多次验证的通用组合# 在 build 目录下执行 configure ../configure \ --prefix/usr/local/gcc-9.5.0 \ --enable-languagesc,c \ --disable-multilib \ --disable-bootstrap逐个解释这些参数--prefix指定安装目录GCC 的二进制、头文件、库文件都会装到这里。我刻意把不同版本的 GCC 装到不同目录比如/usr/local/gcc-9.5.0这样以后想切换或者删除都方便不会和系统自带的 GCC 混在一起。--enable-languages指定要编译的编程语言前端只写c,c可以让编译时间大幅缩短不需要 Fortran、Ada 之类的话就别开。--disable-multilib在 64 位系统上经常用到它的作用是关闭 32 位库的编译支持。很多服务器上缺 32 位依赖库开着 multilib 会在编译后期报错干脆直接关掉。--disable-bootstrap是省时间的关键GCC 默认会用新编译器把自己重新编译三遍bootstrap来验证编译器正确性这个过程非常耗时关闭后只编译一遍省下大量时间。要知道--prefix如果完全不指定默认是/usr/local这意味着 GCC 的头文件会装到/usr/local/include、库文件装到/usr/local/lib很容易和系统自带的文件产生冲突。指定独立目录是最安全的做法代价是在后续使用时需要显式配置 PATH。对于只想要一个能用的 GCC 9.5.0 的人来说独立目录是正确选择。3.3 make 阶段并行编译的 -j 参数怎么选失败了看哪里configure 顺利通过后输出结尾会出现checking for gcc...这类信息最后提示configure: error的话就说明前面哪一步出了问题。一切正常时下一步就是编译。命令很简单# -j 后面的数字按 CPU 核数设置这里是 4 核的机器 make -j4-j后面的数字决定同时运行多少个编译任务。我一般用 CPU 核数或者核数减一。核数可以通过nproc命令获取比如 8 核机器就执行make -j8或make -j7留一个核给系统其他进程避免编译时整个机器卡死。内存吃紧的机器建议把-j调小比如 2GB 内存就用-j2不然内存耗尽后内核的 OOM killer 会挑编译进程杀掉你在终端里看到的报错往往是Killed而不是某个具体的编译错误极具迷惑性。make 过程中如果出现错误不要急着重新跑。往上翻终端输出找到第一个error:的位置那才是根因。GCC 的构建系统在出错时会在终端打印出具体的文件名和错误类型比如缺少头文件、语法错误、磁盘写入失败等等。一个常见做法是make -j4 21 | tee build.log把完整日志存成文件出错后直接搜error:关键字比在终端里翻快得多。编译结束后检查一下编译器是否生成成功# 查看编译生成的 gcc 可执行文件 ./gcc/xgcc -vxgcc是构建过程中生成的临时编译器如果它能打印出版本信息说明核心编译已经成功可以进入安装阶段。3.4 make install 与临时 PATH 验证装完先不急着写进系统安装这一步权限很重要。如果你 configure 时指定的--prefix是/usr/local/gcc-9.5.0这个目录默认归 root 所有那么 make install 就需要 sudo# 安装到指定目录 sudo make install安装完成后/usr/local/gcc-9.5.0/bin目录下应该能看到gcc、g、gcov等可执行文件。在把这个目录写进系统 PATH 之前先手动验证一下新 GGC 能不能正常工作# 直接调用新安装的 gcc /usr/local/gcc-9.5.0/bin/gcc -v这一步很重要它能确认编译器本身是否可用区分于后面要处理的系统是否使用它。如果这里能正常输出版本信息说明编译安装全链路已经打通。下一章要解决的就是如何让这个新编译器成为系统默认这是很多人最容易卡住的地方。4. 装完 GCC 9.5.0 还是旧版本让新编译器真正生效的路径配置4.1 为什么 which gcc 指向的还是老版本装完 GCC 9.5.0 之后在终端里敲gcc -v结果打印的还是系统自带的旧版本号——这是源码编译安装 GCC 后最常见的问题也是搜索热词里gcc升级后为啥还是旧版本说的现象。原因其实很简单你在终端里敲gcc时shell 是根据PATH环境变量从左到右寻找可执行文件的。系统自带的 GCC 在/usr/bin/gcc而/usr/bin几乎一定排在/usr/local/gcc-9.5.0/bin前面shell 找到/usr/bin/gcc就不再往下找了。有一个常见的遮蔽陷阱是:如果你没有设置--prefix安装到了/usr/local那么新 GCC 在/usr/local/bin/gcc。有些系统上/usr/local/bin正好排在/usr/bin之前这样gcc -v会显示新版本看起来升级成功;有些系统上则不是造成同一个操作在不同机器上结果不一致。这就是我坚持用独立目录的原因——避免这种好像装了又好像没装的模糊状态。要确认系统到底用的是哪个 gcc执行which gcc看路径即可。同样which g看 C 编译器。记住PATH的查找顺序就是一切理解了这一点后面排查问题就有明确方向。4.2 用 update-alternatives 管理 gcc 版本Linux 里管理多版本命令的标准工具是update-alternatives。对 GCC 来说需要把gcc、g、cc等符号链接都注册进去。如果用make install直接安装新的 GCC 已经放在了/usr/local/gcc-9.5.0/bin但不会有任何机制自动替换/usr/bin/gcc除非你手动改 PATH 或者用更新替代机制。我常用的注册方式如下# 注册 gcc 9.5.0 sudo update-alternatives --install /usr/bin/gcc gcc /usr/local/gcc-9.5.0/bin/gcc 100 # 注册 g 9.5.0 sudo update-alternatives --install /usr/bin/g g /usr/local/gcc-9.5.0/bin/g 100这里的/usr/bin/gcc是链接要被创建的位置gcc是链接组名/usr/local/gcc-9.5.0/bin/gcc是实际的可执行文件最后的100是优先级。数字越大在自动模式下被选中的可能性越高。如果系统里原本就有/usr/bin/gcc需要先把它也注册进去否则会提示目标文件已存在。注册完可以用下面的命令交互式切换版本# 打开交互式配置界面 sudo update-alternatives --config gcc界面里会列出所有注册过的 GCC 版本输入编号即可切换。切完之后gcc -v应该显示新版本。注意update-alternatives的原理是修改/usr/bin/gcc这个符号链接的指向不影响你手工指定的 PATH 设置两者可以同时存在但混用时容易让人困惑。我个人的习惯是要么只用 update-alternatives要么只用 PATH 配置不要两个一起上。两个方案并存时一旦忘记自己做过什么排查起来非常费劲。4.3 环境变量 PATH 和 LD_LIBRARY_PATH 的配置边界除了update-alternatives另一条路是直接在用户环境变量里加 PATH。适用于你只希望当前用户或者当前会话使用新版本不想动系统的全局设置。配置方法如下# 编辑当前用户的 bash 配置 vim ~/.bashrc # 在文件末尾追加 export PATH/usr/local/gcc-9.5.0/bin:$PATHexport PATH/usr/local/gcc-9.5.0/bin:$PATH的意思是把新 GCC 的 bin 目录加在原有 PATH 前面这样 shell 找 gcc 时会先命中新地址。注意写法是把新目录放在前面放后面的话等于没加。改完配置后执行source ~/.bashrc让它立即生效。但这里有个很容易被忽视的连带问题GCC 编译出的程序运行时依赖libstdc.so.6而这个库在/usr/local/gcc-9.5.0/lib64下不在系统动态链接器默认搜索路径里。如果你编译的程序是给别的机器用的或者当前机器的系统中原本有旧版本libstdc运行新编译的程序时可能报version GLIBCXX_3.4.21 not found。解决办法是设置LD_LIBRARY_PATH# 追加动态库搜索路径 export LD_LIBRARY_PATH/usr/local/gcc-9.5.0/lib64:$LD_LIBRARY_PATH不过LD_LIBRARY_PATH属于能不用就不用的东西它会影响所有从当前 shell 启动的程序。更稳妥的做法是在链接时用 rpath 把库路径写进可执行文件但这属于进阶操作。对于大多数场景只要记住PATH 管的是找 gcc 命令LD_LIBRARY_PATH 管的是找编译出来的程序运行所需的 .so就不会在配置时搞混方向。5. 避坑GCC 9.5.0 源码编译的 5 个典型翻车现场与排查办法5.1 坑configure 报错找不到 gmp.h 或 mpfr.h现象执行 configure 时出现类似configure: error: cannot find gmp.h或cannot find mpfr.h有时候还会附带提示让你用--with-gmp指定路径。原因系统里缺少 GMP、MPFR、MPC 的开发包或者包已安装但 configure 没有在默认路径下找到。多数情况下是第一种只装了运行库没装-devel包。二进制运行库提供.so文件但编译时需要的头文件.h在开发包里。在 Ubuntu 上就是libgmp-dev而不是libgmp10。解决先确认缺失的是哪个库然后安装对应的开发包。Ubuntu 系用sudo apt install libgmp-dev libmpfr-dev libmpc-dev装完后重新执行 configure。如果你是在内网离线环境无法用 apt 安装那就需要手动把这些库的源码也编译一遍然后通过--with-gmp/usr/local/gmp --with-mpfr/usr/local/mpfr --with-mpc/usr/local/mpc告诉 GCC configure 它们的安装位置。5.2 坑make 时出现 cannot compute suffix of object files现象configure 通过了但进入 make 阶段不久输出中出现checking for suffix of object files... configure: error: cannot compute suffix of object files: cannot compile之类的信息。注意这条报错有时候出现在 GCC 自身的 configure 子过程中。原因这通常意味着引导编译器无法正常工作。GCC 在构建过程中会调用系统现有的 C 编译器来编译一些初始工具如果引导编译器有问题——比如gcc命令指向了一个不存在的路径、系统的 GCC 和 G 版本不匹配、或者缺少libc开发包——就会导致无法编译简单的测试程序从而得到这个报错。解决先检查引导编译器是否正常echo int main(){return 0;} | gcc -x c - -o /dev/null能编译通过说明基础工具链没问题。再查libc6-dev是否安装Ubuntu 系统可以直接sudo apt install libc6-dev。还有一种情况是/tmp目录空间不足或权限不对GCC 的 configure 会在/tmp下创建临时目录做编译测试如果「找不到临时目录」也会间接表现为这个错误。5.3 坑内存不足导致 cc1plus 进程被杀死现象make 进行到 C 相关文件时终端突然出现类似cc1plus: fatal error: Killed或者直接提示signal terminated进程退出。原因GCC 编译 C 代码时非常耗内存cc1plus是 C 的前端编译器进程编译某个大文件时可能吃掉 1GB 以上内存。如果机器总内存只有 2GB开了-j4就会导致内存耗尽内核 OOM killer 强行杀掉进程。解决最直接的办法是降低并行度改用make -j1或make -j2。观察一下系统内存free -h如果总内存确实很小还可以通过--disable-bootstrap已经省掉了一轮编译再配合-j1让 GCC 以最低内存消耗完成构建。如果内存实在紧张到连-j1都撑不住那就考虑加 swapsudo fallocate -l 4G /swapfile sudo mkswap /swapfile sudo swapon /swapfile。编译完记得关掉 swap 不是必须的留着也不影响使用但如果你用的是云服务器磁盘 IO 会拖慢编译速度。5.4 坑build 目录与源码目录混用导致重复编译现象第一次 make 出错后你在源码目录里重新执行../configure然后又直接 make结果编译速度反而越来越慢或者出现一些明明改好了还是报同样的错的诡异情况。原因GCC 的构建系统对是否在源码目录里跑过 configure非常敏感。一旦在源码目录里执行过 configure源码目录里就会残留 config 相关文件之后再在 build 目录执行 configure 时GCC 的构建系统会检测到目录状态不干净可能拒绝运行或产生不确定行为。另外在源码目录里直接编译会让源码文件与目标文件混在一起想要彻底清理就得手动删除一堆文件容易漏。解决规范做法是源码目录只保留.tar.gz解压后的原始内容和必要的补丁编译全部在 build 目录完成。如果已经混了最省事的方式是删掉整个解压目录重新解压一份再建新 build 目录。rm -rf gcc-9.5.0之后重新tar -xf速度比手动清理快得多也干净得多。5.5 坑安装后编译器版本没变PATH 写错位置现象按教程配置好 PATH 后gcc -v仍然显示旧版本或者终端里新开一个 shell 就失效了。原因最常见的两类一是把export PATH/usr/local/gcc-9.5.0/bin:$PATH写成了$PATH:/usr/local/gcc-9.5.0/bin新目录放在了后面优先级反而最低二是编辑的是~/.bashrc但当前环境是 Bash 以外的 shell比如 zsh或者修改后没有执行source只是重开了一个终端——重开终端其实会重新加载.bashrc但某些桌面环境启动的 shell 是登录 shell读的是~/.profile而不是~/.bashrc。解决先执行echo $PATH看/usr/local/gcc-9.5.0/bin是否在输出里、以及排在什么位置。如果在但which gcc还是旧的说明顺序不对去检查 export 语句。如果压根没有说明配置没生效或写错文件了。检查你用的是哪个 shellecho $SHELL。如果是 Bash确认~/.bashrc内容如果是其他 shell就写到对应的 rc 文件。改完后source ~/.bashrc再验证。6. 收尾版本共存、切换技巧与验证新安装 GCC 是否可用6.1 一个快速验证 GCC 9.5.0 是否完好的测试安装完成并完成 PATH 配置后我习惯用一段简单的 C 程序做完整验证而不是只看gcc -v就完事。验证要覆盖编译、链接、运行三个阶段因为有些问题只有到链接或运行时才会暴露。#include iostream #include vector #include string int main() { std::vectorstd::string msg {gcc, 9.5.0, works, fine}; for (const auto word : msg) { std::cout word ; } std::cout std::endl; return 0; }# 编译并运行测试程序 g test.cpp -o test ./test能正常输出gcc 9.5.0 works fine说明编译器、标准库头文件、动态链接、运行环境四层都通过了。如果编译能过但运行时报GLIBCXX_3.4.21 not found那就是前面说的LD_LIBRARY_PATH没配好回到 4.3 节处理。这一步跑通了后续用 GCC 9.5.0 编其他项目才是可信的。6.2 需要切换回去时别慌有后悔药用update-alternatives --config gcc切回旧版本后你可能会发现某些依赖新版本编译出来的库的项目运行不了了这是正常的——编译器版本和 ABI 不是完全兼容的。我的习惯是给不同项目单独写构建脚本文件头部显式写明用哪个 gcc。与其在系统层面反复折腾不如让每个项目自己决定用哪个编译器。6.3 一点真实的经验版本号不是万能的GCC 9.5.0 是 GCC 9 系列的最后一个版本bug 修复最全稳定性好。选择它往往是出于项目兼容性的硬要求而不是因为它是最新版本。我遇到过不少次项目方非要 GCC 9.5.0但实际代码用系统默认编译器也能编过——这时候要不要装就值得权衡。编译一套 GCC 的时间成本很高如果只是为了满足某个gcc --version的检查脚本其实可以用前面提到的 PATH 技巧快速伪装一个。但如果真的要编 C17 代码、链接新版 ABI 的库实打实装一个才安心。希望这些踩过的坑和验证方法能帮你在编译 GCC 9.5.0 时少走一些弯路后面编其他 GNU 工具链比如 binutils、gdb时configure、make、make install 这套流程是完全通用的一次会了就都会了。本文还有配套的精品资源点击获取

读完文章,也想定制专属网站?

尧图设计师 24 小时内与您沟通定制方案

免费获取报价 →
↑