资讯详情

手动编译 GCC 9.3.0 实战:C++17 支持与工具链维护

📅 2026/10/15 17:33:10 | 华诺云谱 👁 阅读
手动编译 GCC 9.3.0 实战:C++17 支持与工具链维护
1. 为什么还要手动编译 GCC 9.3.01.1 系统自带编译器不够用的真实场景大部分 Linux 发行版自带的 GCC 版本都偏保守。比如某些长期支持版本默认给的是 GCC 7.x 甚至 5.x这些版本对 C17 的支持是残缺的——std::filesystem还在experimental命名空间里if constexpr可能报错结构化绑定structured bindings时灵时不灵模板推导指引deduction guides更是想都别想。你写了一段自认为标准的 C17 代码结果编译报了一屏错误查半天发现是编译器版本的问题这种体验相当消耗耐心。我当初决定手动编译 GCC 9.3.0就是因为一个项目里用到了std::filesystem做跨平台路径处理系统自带的 GCC 7.5 死活编不过加-lstdcfs也只是把链接错误从一百行减到五十行。与其在代码里到处写兼容宏不如直接把编译器升上去一劳永逸。GCC 9.3.0 这个版本值得选原因有几个它是 GCC 9.x 系列的最后一个维护版本bug 修复比较完整对 C17 的核心特性支持已经全部落地包括std::optional、std::variant、std::any、std::string_view、并行算法等同时它还没有 GCC 10 之后那些比较激进的变化稳定性好作为生产环境的编译器很合适。1.2 手动编译和包管理器安装的取舍有人会问为什么不直接用包管理器装个新版本比如在某些发行版上加个第三方源就能装 GCC 9。这个方案不是不行但有几个隐患第三方源的编译器可能被裁剪过缺少某些语言前端或者库支持不同发行版的打包方式不一样换一台机器就得重新折腾最关键的是你无法控制编译选项比如--enable-languages到底开了哪些语言--with-arch优化到了什么程度这些在排查问题时很重要。手动编译的好处是全程可控。你知道每一个configure参数是什么意思知道装到了哪个路径知道依赖库是哪个版本。出了问题也能定位到具体环节而不是对着包管理器的黑盒干瞪眼。代价就是编译时间长——在一台四核八线程的机器上完整编译 GCC 9.3.0 大概需要四十分钟到一个小时取决于你开了哪些语言前端。如果你只是想在本地跑几个 C17 的小 demo不想折腾编译那用包管理器或者容器镜像里的新版 GCC 完全够用。但如果你需要在特定环境下长期维护一套工具链或者要对编译器的行为做精细控制手动编译是绕不过去的路。2. 编译前的依赖准备与检查2.1 必备依赖库清单GCC 的编译依赖不算特别复杂但缺一个就会在configure或者make阶段报错。下面这张表是我整理的核心依赖按重要性排序依赖库最低版本作用缺失后果GMP4.3.2任意精度算术运算configure 直接失败MPFR2.4.2多精度浮点运算configure 直接失败MPC0.8.0复数运算configure 直接失败ISL0.15循环优化和多项式分析可选但建议装上zlib1.2.3压缩支持链接阶段报错binutils2.30汇编器和链接器编译过程报错make3.80构建工具无法执行构建gcc (旧版)4.8引导编译器无法开始编译GMP、MPFR、MPC 这三个是硬性依赖缺一不可。它们的作用是给 GCC 提供高精度的数学运算能力编译器内部做常量折叠、循环优化的时候会用到。ISL 是可选依赖但如果你想让 GCC 的 Graphite 循环优化框架正常工作最好装上。2.2 依赖库的获取与编译这些依赖库有两种获取方式用系统包管理器装开发版或者从源码编译。我建议优先用包管理器省时间。以常见的包管理器为例# Debian/Ubuntu 系 sudo apt-get install libgmp-dev libmpfr-dev libmpc-dev libisl-dev zlib1g-dev # RHEL/CentOS 系 sudo yum install gmp-devel mpfr-devel libmpc-devel isl-devel zlib-devel如果包管理器里的版本太老或者你需要在没有 root 权限的环境下安装那就得从源码编译。源码编译的顺序很重要先 GMP再 MPFR最后 MPC因为 MPFR 依赖 GMPMPC 依赖 GMP 和 MPFR。编译时统一指定安装前缀比如$HOME/local方便后续管理。# 以 GMP 为例 tar -xvf gmp-6.2.0.tar.xz cd gmp-6.2.0 ./configure --prefix$HOME/local --enable-cxx make -j$(nproc) make installMPFR 编译时需要指定 GMP 的路径./configure --prefix$HOME/local --with-gmp$HOME/localMPC 同理需要同时指定 GMP 和 MPFR./configure --prefix$HOME/local --with-gmp$HOME/local --with-mpfr$HOME/local这里有个容易踩的坑编译完依赖库之后一定要把$HOME/local/lib加到LD_LIBRARY_PATH里否则后续编译 GCC 时链接器找不到这些库。可以在~/.bashrc里加一行export LD_LIBRARY_PATH$HOME/local/lib:$LD_LIBRARY_PATH然后source一下。2.3 磁盘空间与内存的硬性要求编译 GCC 是个资源密集型任务提前检查一下磁盘和内存很有必要。源码包解压后大概 800MB 左右但构建目录会膨胀到 3GB 到 5GB安装目录又要 2GB 到 3GB。所以至少预留 10GB 的磁盘空间比较稳妥。内存方面make的时候如果并行度开太高每个编译进程都会吃内存。我实测下来-j4的情况下峰值内存占用大概在 2GB 到 3GB。如果机器只有 2GB 内存建议用-j1或者-j2虽然慢一点但不会因为 OOM 被系统杀掉进程。被 OOM Killer 干掉编译进程的体验很差因为没有任何错误提示就是突然中断了。3. GCC 9.3.0 的配置与编译实操3.1 configure 参数逐条解读下载好 GCC 9.3.0 的源码包之后解压到一个目录然后在源码目录之外新建一个构建目录。这一点很重要GCC 官方推荐 out-of-tree 构建避免污染源码目录也方便出错后直接删掉构建目录重来。tar -xvf gcc-9.3.0.tar.xz mkdir gcc-9.3.0-build cd gcc-9.3.0-build接下来是configure命令我把自己用的参数列出来然后逐条解释../gcc-9.3.0/configure \ --prefix$HOME/gcc-9.3.0 \ --enable-languagesc,c \ --disable-multilib \ --with-gmp$HOME/local \ --with-mpfr$HOME/local \ --with-mpc$HOME/local \ --with-isl$HOME/local \ --enable-checkingrelease \ --disable-bootstrap--prefix指定安装路径我习惯装到用户目录下避免污染系统目录也不需要 root 权限。--enable-languagesc,c只编译 C 和 C 前端如果你需要 Fortran 或者 Go可以加上对应的语言名但编译时间会显著增加。--disable-multilib关掉 32 位库的编译除非你确实需要编译 32 位程序否则关掉能省不少时间。--with-gmp等参数指定依赖库的路径如果你是用包管理器装的依赖这些可以省略configure会自动找到。--enable-checkingrelease关掉编译器的内部断言检查生成的编译器会快一些适合生产使用。--disable-bootstrap是争议比较大的一个选项——bootstrap 会用刚编译出来的编译器再编译一遍自己验证编译器的正确性但会让编译时间翻倍。如果你对编译器质量要求极高可以不加这个参数如果只是日常使用关掉能省一半时间。3.2 编译过程中的资源控制configure跑完之后会生成 Makefile。接下来就是make了。这里的关键是控制并行度make -j$(nproc) 21 | tee build.log-j$(nproc)会按照 CPU 核心数开并行任务速度最快。但前面说过内存不够的时候要降并行度。另外把输出重定向到build.log是个好习惯编译过程中如果报错可以回头翻日志不用在终端里往上滚。编译过程中有几个阶段特别慢libstdc-v3的编译、stage1的编译器构建、以及最后的libgcc和libstdc的链接。这几个阶段 CPU 和内存占用都会飙升机器可能会变得很卡属于正常现象。如果你在编译过程中看到某个文件编译了很久没动静不要急着 CtrlC。GCC 的某些源文件比如insn-emit.c生成和编译都很耗时耐心等一等。我见过有人以为卡死了就中断结果白编译了半小时。3.3 安装与验证编译完成后执行安装make install安装过程比较快主要是拷贝文件。装完之后把$HOME/gcc-9.3.0/bin加到PATH的最前面确保优先使用新编译器export PATH$HOME/gcc-9.3.0/bin:$PATH然后验证版本gcc --version g --version如果输出显示gcc (GCC) 9.3.0说明安装成功。接下来写一个测试文件验证 C17 特性是否可用#include filesystem #include optional #include variant #include iostream int main() { std::filesystem::path p /tmp/test; std::optionalint opt 42; std::variantint, std::string var hello; std::cout path: p std::endl; std::cout opt: opt.value() std::endl; std::cout var: std::getstd::string(var) std::endl; return 0; }编译命令g -stdc17 -o test_cpp17 test_cpp17.cpp ./test_cpp17如果编译通过并且运行输出正常说明 GCC 9.3.0 的 C17 支持已经就绪。注意std::filesystem在 GCC 9 里已经不需要额外链接-lstdcfs了这是 GCC 8 和 9 的一个重要区别。4. C17 与 C17 特性在 GCC 9.3.0 上的实测表现4.1 C17 特性的支持情况C17也叫 C18本质上是对 C11 的一个小修订没有引入大的新特性主要是修复了一些缺陷、澄清了一些模糊表述。GCC 9.3.0 对 C17 的支持是完整的用-stdc17或者-stdiso9899:2017就能启用。C17 里比较值得关注的改动包括_Generic的改进、_Static_assert的完善、以及对原子操作的进一步规范。这些改动在日常编码中感知不强但如果你写的是需要严格符合标准的库代码用 C17 比 C11 更稳妥。实测下来GCC 9.3.0 在-stdc17模式下编译大型 C 项目比如一些开源的基础库没有遇到任何问题。-pedantic模式下也没有额外的警告说明标准符合度很高。4.2 C17 核心特性的实测清单C17 引入的特性比较多我挑几个最常用的在 GCC 9.3.0 上逐个验证特性头文件GCC 9.3.0 支持备注结构化绑定语言特性完整支持auto [a, b] pair;if constexpr语言特性完整支持编译期分支std::optionaloptional完整支持可能为空的返回值std::variantvariant完整支持类型安全的联合体std::anyany完整支持任意类型容器std::string_viewstring_view完整支持非拥有字符串视图std::filesystemfilesystem完整支持无需额外链接并行算法algorithm需要 TBB链接-ltbb折叠表达式语言特性完整支持(args ...)类模板参数推导语言特性完整支持std::pair p{1, 2};并行算法这一项需要特别注意。GCC 9.3.0 的并行算法实现依赖 Intel TBBThreading Building Blocks如果你要用std::execution::par策略需要安装 TBB 并在编译时链接-ltbb。如果没装 TBB编译会报错说找不到tbb/tbb.h。这是很多人容易忽略的一个依赖。4.3 从 C14 迁移到 C17 的注意事项如果你手上有 C14 的代码要迁移到 C17有几个地方需要留意。首先是std::auto_ptr在 C17 里被正式移除了如果代码里还在用编译会直接报错需要换成std::unique_ptr。其次是std::random_shuffle也被移除了要换成std::shuffle。另外C17 对noexcept的检查更严格了某些在 C14 下能编过的代码在 C17 下可能会因为异常规格不匹配而报错。遇到这种情况检查一下函数声明和定义里的noexcept是否一致。还有一个比较隐蔽的变化C17 引入了保证的拷贝省略guaranteed copy elision某些依赖拷贝构造函数的代码行为会发生变化。比如T obj T();在 C17 里不会调用拷贝构造函数而是直接在目标位置构造。如果你的类依赖拷贝构造函数做副作用迁移时要注意。5. 常见编译问题与排查技巧5.1 configure 阶段的典型报错报错一找不到 GMP/MPFR/MPCconfigure: error: Building GCC requires GMP 4.2, MPFR 2.4.0 and MPC 0.8.0.这个报错通常是因为依赖库没装或者装了但configure找不到。解决办法确认依赖库的安装路径然后用--with-gmp、--with-mpfr、--with-mpc显式指定。如果依赖是装在非标准路径下的还要确保LD_LIBRARY_PATH包含了对应的lib目录。报错二C 编译器缺失configure: error: C compiler missing or inoperationalGCC 的构建过程需要用一个已有的 C 编译器来编译部分工具。如果系统里只有 C 编译器没有 C 编译器就会报这个错。装一个g就行。报错三ISL 版本不匹配configure: error: ISL version 0.15 or later is requiredISL 的版本要求比较严格太老的不行。如果包管理器里的 ISL 版本不够就从源码编译一个。ISL 本身编译很快几分钟就能搞定。5.2 make 阶段的典型报错报错一内存不足被 killedmake: *** [Makefile:xxx: xxx] Killed没有其他错误信息就是 Killed基本可以确定是 OOM。解决办法是降低并行度用-j2或者-j1重新编译。如果已经编译了一部分不用删掉构建目录直接重新make就行已经编译好的目标文件不会重复编译。报错二链接时找不到依赖库undefined reference to __gmpz_init这是链接器找不到 GMP 库的符号。检查LD_LIBRARY_PATH是否包含了 GMP 的lib目录或者用-L参数显式指定库路径。有时候还需要用-Wl,-rpath把库路径写进可执行文件里避免运行时找不到。报错三编译到一半磁盘满了No space left on device这个没什么好说的清理磁盘空间或者换一个分区重新来。建议在开始编译之前就用df -h检查一下可用空间。5.3 安装后的运行时问题问题一新编译器找不到标准库头文件装完 GCC 9.3.0 之后编译一个简单的 C 程序报错说找不到iostream。这通常是因为PATH里新编译器的路径没放对或者CPLUS_INCLUDE_PATH被旧编译器污染了。检查which g的输出确认指向的是新编译器的路径。问题二链接时用了旧版的 libstdc程序编译通过但运行时崩溃报错说GLIBCXX_3.4.26 not found。这是因为运行时链接器找到了系统自带的旧版libstdc而不是新编译器配套的那个。解决办法是在链接时加上-Wl,-rpath,$HOME/gcc-9.3.0/lib64把新库的路径写进可执行文件。问题三并行算法链接失败用了std::execution::par但链接报错提示找不到 TBB 的符号。确认 TBB 是否安装编译时是否加了-ltbb。如果 TBB 装在非标准路径还要加-L和-Wl,-rpath。我踩过最坑的一个问题是编译出来的程序在本地跑得好好的放到另一台机器上就报GLIBCXX版本不匹配。后来发现是那台机器上的libstdc太老。解决办法要么是静态链接libstdc加-static-libstdc要么是把新版的libstdc一起打包过去。静态链接最省事但可执行文件会大一些。6. 工具链的长期维护建议6.1 多版本 GCC 的共存管理手动编译的 GCC 装在用户目录下和系统自带的编译器天然隔离这本身就是一种共存方案。但如果你需要频繁切换不同版本的 GCC手动改PATH就比较麻烦了。可以用update-alternatives来管理或者写一个简单的 shell 函数use_gcc() { export PATH$HOME/gcc-$1/bin:$PATH export LD_LIBRARY_PATH$HOME/gcc-$1/lib64:$LD_LIBRARY_PATH }这样use_gcc 9.3.0就能切到 9.3.0use_gcc 11.2.0就能切到 11.2.0。切换之后用gcc --version确认一下。6.2 编译产物的清理与空间回收GCC 的构建目录很大装完之后如果不需要保留构建中间产物可以直接删掉构建目录能回收好几个 GB 的空间。安装目录本身大概 2GB 到 3GB如果磁盘紧张可以删掉一些不常用的语言前端和文档。另外make install之后源码目录和构建目录都可以删掉只保留安装目录就行。如果以后需要重新编译重新解压源码包即可。6.3 什么情况下值得升级到更新的版本GCC 9.3.0 对 C17 的支持已经足够完整但如果你要用 C20 的特性比如 concepts、ranges、coroutines那就需要 GCC 10 或更高版本。GCC 10 对 C20 的支持是实验性的GCC 11 和 12 才比较完善。我的建议是如果项目锁定在 C17GCC 9.3.0 可以用很长时间没必要追新。如果项目计划迁移到 C20那直接上 GCC 11 或 12跳过 10。每次大版本升级都会带来一些不兼容的变化升级之前先在测试环境里跑一遍完整的编译和测试确认没有问题再推到生产环境。编译 GCC 这件事第一次做会觉得步骤繁琐但走通一遍之后后面再编译其他版本就是重复劳动了。把依赖装好、参数配对、日志留好基本不会出大问题。真正耗时的就是编译本身泡杯茶等着就行。
📝

华诺云谱内容团队

资深建站顾问 · 行业研究员

10年+企业数字化服务经验,专注智能建站、SEO优化与品牌营销,持续输出建站技巧、行业洞察与营销干货,已帮助5000+企业实现数字化增长。

你可能需要的服务

订阅华诺云谱资讯周报

每周一封,精选建站技巧、SEO与营销干货,直达邮箱。已有 8,000+ 企业主订阅,助你少走弯路。

↑