Ubuntu 20.04源码编译升级GCC 12.2:依赖配置与多版本切换实战

发布时间:2026/9/16 21:56:22
Ubuntu 20.04源码编译升级GCC 12.2:依赖配置与多版本切换实战 这台机器是 Ubuntu 20.04我执行了apt install gcc -y装完以后gcc --version停在 9.4.0。一开始没当回事直到我下载了一个要求 GCC 11 的 C20 项目configure 阶段直接被 “compiler too old” 拦了下来。再去查 apt官方源里虽然有 gcc-10、gcc-11 的可用包但 12.x 这个版本只能走源码安装。我当时翻了大量资料踩了依赖缺、configure 报错、make 被 OOM Kill、装完 gcc 还是旧版本这一连串坑最后把 GCC 12.2.0 完整装好并平滑切换到系统默认。这篇就是这次全过程的实操记录适合所有在 Ubuntu 20.04 上需要新版 GCC 的人尤其是准备编译新版 Python、OpenSSL、CUDA 工具链或者对 C20 特性有要求的开源项目的人。1. 为什么Ubuntu 20.04自带的gcc会被项目嫌弃1.1 apt install gcc拿到的是9.4.0Ubuntu 20.04 的代号是 Focal Fossa它发布时的默认 GCC 是 9.x 系列。执行apt install gcc -y后装上的实际上是gcc-9具体版本是 9.4.0随着安全更新会继续小幅滚动但不会跨大版本。如果只做日常编译9.4.0 完全够用。真正出问题的是下面这类情况项目代码用了 GCC 11 才完善的 C20 协程、模块特性或者某个构建脚本直接检测__GNUC__ 11那 GCC 9 在 configure 阶段就会被判死刑。还有一个隐蔽的坑GCC 9 的libstdc对 C20format、ranges支持不完整你就算手动加-stdc20还是会有大段头文件报错。另一个很多人忽略的问题是兼容性矩阵。新版 CUDA 工具链、新版 GCC 编译出的动态库会反向拉着系统里的软件一起升级。如果你正在编译一个对 ABI 敏感的底层库旧编译器编出来的产物很可能在链接阶段和新代码打起来。1.2 哪些场合必须编译新版gcc不是所有项目都要最新版但以下几个场景我实测过GCC 12.2 几乎是硬需求编译较新的 Linux 内核内核 5.16 以后的某些版本在配置时会检查 GCC 版本特别是对-Werror和代码生成质量有要求老编译器容易触发编译警告直接中断。编译新版 PythonPython 3.11、3.12 源码在部分优化选项上GCC 12 生成的代码比 GCC 9 有明显效率差异而且某些平台检测会要求 GCC 11。C20 重度项目协程Coroutines、概念Concepts、std::format、std::ranges这些特性在 GCC 12 里才达到可用的完成度GCC 11 都还有不少 bug。新版 OpenSSL / Boost / LLVM 构建依赖链一旦有一环是新标准编译的后面跟进的库基本都被迫升级到同一代编译器。说白了源码安装 GCC 12.2 不是为了折腾而是为了在这个 LTS 系统上打开一条继续编译新项目的通道。而且源码安装不污染系统想看新版本随时切不想用了直接换回 GCC 9。2. 编译前的系统准备依赖包与源码下载2.1 一次性装齐三件套依赖GCC 的源码编译要求系统里必须有 GMP、MPFR、MPC 这三个数学库它们的头文件和链接库一个都不能少。很多人直接解压源码后跑./configure结果第一屏就报错configure: error: Building GCC requires GMP 4.2, MPFR 2.4.0 and MPC 0.8.0.这就是缺依赖的典型表现。在 Ubuntu 20.04 上正确处理是先用 apt 装好sudo apt update sudo apt install -y build-essential libgmp-dev libmpfr-dev libmpc-dev flex bisonbuild-essential会带上 make、g 和基础头文件libgmp-dev、libmpfr-dev、libmpc-dev就是那三个数学库的开发包。flex 和 bison 用于生成部分解析器代码虽然现在 GCC 源码里自带了生成好的文件但装上只有好处没有坏处。这里有一个容易踩的版本问题Ubuntu 20.04 软件源里这三个库的版本比较老但满足 GCC 12.2 的需求。比如 libmpc-dev 是 1.1.0GCC 需要的下限是 0.8.0够用。不需要为了编译 GCC 去手动升级系统里的 GMP 和 MPFR那样反而可能破坏系统里其他依赖它们的软件。2.2 GCC 12.2源码获取与校验GCC 12.2.0 是 2022 年 8 月发布的 bugfix 版本修复了 12.1 里一堆 C 前端问题比装 12.1 稳得多。源码包下载地址是在 GNU 官方 FTP 镜像站国内从清华或中科大镜像拉同样是官方源码速度会更快# 官方入口国外机器可用 wget https://ftp.gnu.org/gnu/gcc/gcc-12.2.0/gcc-12.2.0.tar.xz # 国内镜像入口速度更友好 wget https://mirrors.tuna.tsinghua.edu.cn/gnu/gcc/gcc-12.2.0/gcc-12.2.0.tar.xz wget https://mirrors.ustc.edu.cn/gnu/gcc/gcc-12.2.0/gcc-12.2.0.tar.xz下载完后建议先做一次 SHA256 校验防止下载过程中文件损坏。去镜像站同目录下把gcc-12.2.0.tar.xz.sha256拉下来然后执行sha256sum gcc-12.2.0.tar.xz cat gcc-12.2.0.tar.xz.sha256对比两个哈希值一致再解压tar -xf gcc-12.2.0.tar.xz cd gcc-12.2.0解压后的源码目录大概 1GB 左右编译后整体占空间 5GB 到 6GB编译前先确认下磁盘余量。VPS 用户尤其注意df -h看一眼少于 10GB 剩余空间的项目编译到一半被磁盘写满会非常被动。3. configure参数选型直接决定安装成败的细节3.1 每个关键参数背后的理由GCC 的 configure 参数比大多数开源项目都讲究。无脑默认全选不是不行但会多消耗大量编译时间。我根据自己的需求逐项说明--prefix/opt/gcc-12.2.0指定安装目录。我刻意不用/usr/local因为 Ubuntu 的/usr/local会和系统搜索路径纠缠测试环境无所谓生产服务器上容易出乱子。装在/opt/gcc-12.2.0的定义是“这玩意是手工安装的独立软件”管理起来清爽卸载直接删目录。--enable-languagesc,c,fortran只编译 C、C 和 Fortran。GCC 还支持 Go、Ada、D 等语言前端除非你真的需要否则别开。每多一种语言编译时间就多一大截。--disable-multilib禁用 32 位库支持。GCC 默认会试图保留多架构 lib 支持这要求系统里装有 32 位开发包一旦缺库就是 configure 报错。我们是在 64 位系统上编 64 位编译器直接禁用最省事。--disable-nls禁用 Native Language Support。翻译文件生成既慢又没有实际意义大多数开发环境用英文报错足够。--enable-checkingrelease只在编译阶段启用关键检查不启用冗余断言这是发行版的标准做法。--enable-threadsposix显式指定 POSIX 线程模型避免某些环境下默认值不是我们想要的。3.2 我的完整configure命令参考建议在源码目录外单独建一个 build 目录避免源码目录里残留大量编译产物cd ~/gcc-12.2.0 # 上一步解压出来的源码根目录 mkdir build cd build ../configure \ --prefix/opt/gcc-12.2.0 \ --enable-languagesc,c,fortran \ --disable-multilib \ --disable-nls \ --enable-checkingrelease \ --enable-threadsposix你的输出如果是以一排checking ...开头最后没有任何error最后几行出现Configuration is ready之类的提示说明成功了。这一步卡住最多的就是缺 GMP/MPFR/MPC报错后回头执行 2.1 的安装命令就能解决。如果网络条件允许、系统里装库不方便源码根目录还提供了另一个官方方案cd ~/gcc-12.2.0 ./contrib/download_prerequisites这个脚本会自动下载 GCC 依赖的 GMP、MPFR、MPC、ISL 源码到当前目录并在 configure 时自动使用本地源码。但脚本执行依赖外网下载网络不稳定时容易失败所以我更倾向直接用系统 apt 包。4. 漫长的make等待与安装落位4.1 并行编译的资源和心态控制configure 通过后执行make。这里我必须强调一句GCC 编译是整个过程中最耗时的环节没有之一。并行编译参数用-j指定进程数最简单的是nprocmake -j$(nproc)但是-j$(nproc)有个前提条件内存要足够。GCC 编译的每个编译进程大约吃 1.5GB 到 2GB 内存一个 8 核 16GB 内存的机器跑-j8没问题只有 4GB 内存的小 VPS 直接跑-j4大概率中途 OOM表现为某个阶段进程无端消失最后终端里冒出来Killed。我的建议是根据内存反推并行线程数内存大小建议make参数大致耗时8核机器2GBmake -j15小时以上4GBmake -j23~4小时8GBmake -j41.5~2小时16GBmake -j$(nproc)40分钟~1小时编译之前先把没用的程序关了。我这里还多做了两步用nice -n 10 make -j4把 GCC 编译进程的优先级降低再用watch -n 10 free -h开另一个终端盯内存。这样即使编译过程中我想继续干别的机器也不会卡到没法操作。4.2 make install之后的目录结构编译顺利结束后执行安装sudo make install这一步会往/opt/gcc-12.2.0下写入目录。装完看一眼结构ls /opt/gcc-12.2.0/bin能看到c、gcc、g、gfortran等可执行文件。这里要特别说明源码安装的 GCC 12.2 默认二进制名就是gcc不是某些教程里说的gcc-12。如果你不改变 PATH直接执行gcc找到的还是系统旧版这两个版本同时存在于文件系统里互不干扰。再验证一下绝对路径/opt/gcc-12.2.0/bin/gcc --version输出应该是gcc (GCC) 12.2.0到这里编译器本体已经生效但距离“日常直接敲 gcc 就是新版”还差一步配置操作。5. gcc升级后还是旧版本PATH与多版本切换的完整解法5.1 先搞清楚which gcc到底指向谁装完新 GCC 后十有八九会遇到这种疑惑明明装了敲gcc --version还是 9.4.0。原因很简单shell 执行gcc时是在$PATH环境变量列出的目录里从前往后找当前$PATH里/usr/bin基本排在最前面系统默认的 gcc-9 被优先找到了。排查方法是which gcc type -a gccwhich gcc只显示第一个匹配项大概率是/usr/bin/gcc。type -a gcc会把所有路径都列出来你能看到/usr/bin/gcc和/opt/gcc-12.2.0/bin/gcc并存。想要新版本胜出方案有两个原理都是改搜索顺序。5.2 用update-alternatives优雅切换最简单粗暴的方法是改 PATH把/opt/gcc-12.2.0/bin放到最前面再写入~/.bashrc。但这种方法在多版本切换时不够灵活我推荐用 Ubuntu 自己的update-alternatives机制sudo update-alternatives --install /usr/bin/gcc gcc /opt/gcc-12.2.0/bin/gcc 120 sudo update-alternatives --install /usr/bin/g g /opt/gcc-12.2.0/bin/g 120 sudo update-alternatives --install /usr/bin/gfortran gfortran /opt/gcc-12.2.0/bin/gfortran 120数字 120 是优先级数字越大优先级越高。然后执行交互配置sudo update-alternatives --config gcc屏幕上会列出所有可用gcc路径输入对应编号选新版。同理处理g和gfortran。验证gcc --version g --version which gccgcc --version这时候应该显示 12.2.0which gcc指向/usr/bin/gcc再ls -l /usr/bin/gcc能看到它其实是指向/etc/alternatives/gcc的软链接最终指向/opt/gcc-12.2.0/bin/gcc。这里要补一个易漏项动态库搜索路径。GCC 12.2 编出来的程序运行时需要新版libstdc.so.6如果系统里没有这个路径执行程序会报找不到动态库。先确认库位置ls /opt/gcc-12.2.0/lib64 | grep libstdc然后在~/.bashrc里追加export LD_LIBRARY_PATH/opt/gcc-12.2.0/lib64:$LD_LIBRARY_PATH5.3 为什么不建议直接替换系统的gcc-9很多人喜欢一不做二不休把/usr/bin/gcc直接删掉或者软链成新版。我强烈不建议这么做。Ubuntu 20.04 系统里大量编译好的内核模块、DKMS 驱动、系统工具链它们对应的是 GCC 9 生成的 ABI强行替换默认 gcc 后系统升级内核模块或重新编译 DKMS 模块时会匹配不上轻则警告重则编译出来的模块加载失败。正确姿势永远是把新版 GCC 安装为“额外可用版本”用update-alternatives管理默认指向。万一系统某个环节需要旧版本执行sudo update-alternatives --config gcc切回去就行整个过程一分钟内解决。6. 源码编译gcc的高频报错与排查记录6.1 configure阶段GMP/MPFR/MPC缺失前面提过的最常见错误这里展开说排查思路configure: error: Building GCC requires GMP 4.2, MPFR 2.4.0 and MPC 0.8.0.先检查系统库是否真的安装了dpkg -l | grep libgmp dpkg -l | grep libmpfr dpkg -l | grep libmpc确认缺哪个就装哪个的开发版注意是-dev包不是普通运行库sudo apt install -y libgmp-dev libmpfr-dev libmpc-dev依赖装齐后重新进入 build 目录清掉残留配置再跑一次 configurecd ~/gcc-12.2.0/build make distclean ../configure ...如果 apt 安装环境受限再回退到./contrib/download_prerequisites方案。6.2 make阶段被OOM Kill编到一半终端突然没有滚动输出最后几行是g: fatal error: Killed signal terminated program cc1plus或者整个 shell 直接显示Killed。这是内存不足编译进程被系统 OOM Killer 干掉。解决办法不是加编译参数而是降低并行度make -j1内存实在不够又坚持要快的可以给系统加 swapsudo fallocate -l 4G /swapfile sudo chmod 600 /swapfile sudo mkswap /swapfile sudo swapon /swapfile加了 4G swap 后2G 内存的小机器也能跑make -j2只是速度依然感人。另一个备选方案是 configure 时加--disable-bootstrap跳过 GCC 的三次自举编译时间能省三分之一代价是编译器自身的可靠性检查缺失非极端情况不建议。6.3 新版程序运行时找不到libstdc.so.6GCC 12.2 编译出的a.out在别的机器或者当前系统默认环境里运行时可能报error while loading shared libraries: libstdc.so.6: cannot open shared object file: No such file or directory原因前面提过新版libstdc动态库路径不在系统默认搜索目录里。除了手动export LD_LIBRARY_PATH更一劳永逸的办法是把路径写入 ld 配置echo /opt/gcc-12.2.0/lib64 | sudo tee /etc/ld.so.conf.d/gcc-12.2.0.conf sudo ldconfig写完后不再需要LD_LIBRARY_PATH系统就能找到新版 C 动态库。注意如果 64 位库目录在你的机器上是lib而不是lib64先确认ls /opt/gcc-12.2.0里的实际目录名别写错。7. 编译完成后的环境变量配置与使用建议7.1 让PATH和动态库永久生效补全~/.bashrc是最稳妥的收尾# GCC 12.2.0 export PATH/opt/gcc-12.2.0/bin:$PATH export C_INCLUDE_PATH/opt/gcc-12.2.0/include:$C_INCLUDE_PATH export CPLUS_INCLUDE_PATH/opt/gcc-12.2.0/include:$CPLUS_INCLUDE_PATH export LD_LIBRARY_PATH/opt/gcc-12.2.0/lib64:$LD_LIBRARY_PATH保存后source ~/.bashrc即可。这里注意 PATH 的写法是把新目录放在原有路径前面如果写反了gcc还是会命中/usr/bin/gcc到时候又是一通排查。建议每次打开新终端都执行一下which gcc gcc --version可以顺手用一段 C20 代码验证新编译器的标准支持cat test.cpp EOF #include iostream int main() { std::cout __cplusplus std::endl; } EOF /opt/gcc-12.2.0/bin/g -stdc20 test.cpp -o test ./test输出202002L说明 C20 模式正常启用。7.2 不同构建系统的gcc指定方式升级完默认 gcc 后很多项目构建时还是会“自作聪明”地去找系统旧编译器因为 CMake 等工具会在第一次 configure 时缓存编译器路径。处理方式是在构建时显式指定# CMake 项目 cmake -DCMAKE_C_COMPILER/opt/gcc-12.2.0/bin/gcc \ -DCMAKE_CXX_COMPILER/opt/gcc-12.2.0/bin/g .. # 环境变量方式 export CC/opt/gcc-12.2.0/bin/gcc export CXX/opt/gcc-12.2.0/bin/g此前踩过的一个具体坑是CMake 项目已经用旧 GCC 9 configure 过一次升级 GCC 12.2 后直接make链接阶段出现大量undefined reference to std::...这就是 CMakeCache 里残留了旧的编译器路径和编译选项。此时必须把CMakeCache.txt删掉重新 configure而不是硬着头皮 make。7.3 清理编译产物与维护建议编译完并验证可用后源码目录和 build 目录里有大量中间文件可以清理cd ~/gcc-12.2.0/build make clean cd ~ rm -rf ~/gcc-12.2.0/opt/gcc-12.2.0是最终安装目录不能动。如果以后想彻底卸载 GCC 12.2直接删掉这个目录再从update-alternatives里移除对应的 entries 就行系统恢复原样几乎不留痕迹。实际使用过程中我会保留源码目录到下一个版本的 GCC 发布。GCC 大版本升级后部分第三方 C 库的 ABI 会有细微变化如果新项目链接老库时报版本相关错误优先检查动态库搜索路径而不是急着重新编译整个依赖链。最后分享一个我在实际操作里养成的小习惯每次源码编译大型项目第一步先把 configure 命令和输出日志存到本地文件比如configure.log、make.log。报错的时候不是盯着屏幕满屏翻而是grep -i error make.log定位问题快得多。这个习惯在我编译 GCC 12.2 的整个过程中帮我省了大量时间尤其是 1000 多行的 configure 输出里找一个error:靠肉眼纯属折磨。

关于本文作者

来自尧图内容编辑团队

尧图内容编辑团队 内容团队

尧图内容编辑团队

本文由尧图网络内容编辑团队执笔。团队由资深项目经理、前端工程师与设计师组成,所有内容均来自亲手交付的真实项目,先讲清问题、再给出可落地的解法。尧图深耕北京网站建设十年,服务过京华建材集团、智造科技等各行业客户,把一线经验沉淀为可复用的行业观察。

  • 十年建站经验,覆盖建材、制造、服务、文创等
  • 项目经理把关选题与事实准确性
  • 工程师与设计师联合撰写专业细节
  • 统一编辑规范,保证文风与排版一致
  • 每月复盘转化数据,迭代选题方向

延伸阅读

相关资讯与近期热门内容

深度阅读推荐

建站决策前值得细读的三篇

网站改版的5个关键决策
2024-08-12

网站改版的5个关键决策

什么时候该改版、改到什么程度、如何避免流量掉光,京华建材集团改版复盘给出答案。

获取专属建站方案

看完文章,把您的行业与预算告诉我们,免费获取一份量身定制的官网建设方案与报价。

立即免费咨询