资讯动态

麒麟V10源码编译升级GCC 9.3.0完整指南:依赖、参数与踩坑记录

发布时间:2026/9/28 5:49:32 来源:尧图企业网站定制
上个月同事过来找我说新项目在麒麟V10服务器上怎么都编不过报错里全是C17语法不支持。我上服务器一看gcc --version显示的版本还是老版本系统自带的工具链满足不了新项目的编译需求。这种情况在国产化服务器环境里挺普遍的麒麟V10默认GCC整体偏保守要么守着旧工具链要么自己动手升一版。于是就有了这次完整的GCC 9.3.0升级记录重点放在依赖下载、编译参数、环境变量配置以及各种来回踩到的坑。不管你是x86_64还是飞腾、鲲鹏的ARM64机器这套流程基本通用。1. 麒麟V10上GCC版本的现状与升级必要性1.1 先给服务器做个体检银河麒麟V10服务器版并不是只有一个技术底座有基于RHEL系演化的版本也有基于其他发行版改造的。这就带来一个现象同样叫“麒麟V10”默认GCC版本可能不一样。有的机器显示4.8.5有的显示8.x少数甚至已经带了9.x。所以升级前第一步永远不是下载源码而是先摸清当前环境cat /etc/os-release gcc --version uname -m rpm -qa | grep -E ^(gcc|glibc|binutils|make)这个步骤看着基础但它能避免后面很多连锁问题。比如有人拿着RHEL系的思路在基于其他源的机器上配yum或者拿到aarch64架构之后照抄x86的库路径。先花两分钟确认系统版本、CPU架构、当前GCC位置、是否装了make和gcc-c后面编译时才心里有数。我看过不少编译到一半才报错的情况追根溯源都是环境没摸清。系统包里没有make就直接跑./contrib/download_prerequisites那个脚本本身依赖wget和perl缺了也会卡死。所以体检时顺手把wget、perl、m4、bzip2这些基础工具也确认一遍没有就先用系统包管理器补上。1.2 升级GCC不是只能替换系统工具链很多第一次做GCC升级的人第一反应是直接改系统自带的GCC或者从软件源里装新版本。这里我要明确说在麒麟V10生产服务器上我不推荐直接替换系统GCC。原因有三。第一系统GCC可能被大量系统软件依赖很多rpm包在安装或升级时会检查GCC版本你把它换掉可能引起意想不到的连锁反应。第二业务需要的是“能编译C17/20项目的工具链”不是整个操作系统的编译器基线没必要动那么大的范围。第三独立安装新GCC到一个特定目录将来要回滚只删目录就行而替换系统包以后回滚极其痛苦。这次升级方案很简单源码编译GCC 9.3.0安装到/opt/gcc-9.3.0通过环境变量让它在需要时优先生效。系统自带的GCC保留在/usr/bin互不干扰。2. 离线依赖准备gmp/mpfr/mpc才是第一个坑2.1 编译GCC为什么绕不开这三个库GCC的数学运算能力不是自己从头实现的它依赖三个GNU基础库GMP任意精度算术库负责大整数和有理数运算。MPFR在GMP之上提供实数浮点运算并保证正确的舍入语义。MPC在MPFR之上做复数运算支持。这三个库是编译GCC的硬性依赖。缺少任何一个configure阶段就会直接报错信息通常是Building GCC requires GMP 4.2, MPFR 2.4.0 and MPC 0.8.0。我见过有人拿着这个报错去网上搜“GMP冲突”折腾半天其实只是源码目录里少放了依赖而已。另外还有一个isl库它负责GCC的Graphite循环优化框架。但isl在GCC编译里属于可选依赖没有它也能编过只是--with-isl相关优化功能不会启用。所以生产环境求稳的话先保证gmp、mpfr、mpc三件套到位就够用。2.2 依赖版本的匹配与下载校验GCC 9.3.0源码里自带一个下载依赖的脚本./contrib/download_prerequisites它会自动检查并下载与版本匹配的gmp、mpfr、mpc。脚本默认的版本组合大致是gmp-6.1.0、mpfr-3.1.4、mpc-1.0.3。在有外网的机器上进入解压好的gcc-9.3.0目录跑一次脚本就行cd /usr/local/src/gcc-9.3.0 ./contrib/download_prerequisites如果服务器在内网这个脚本多半会卡在下载上。这时候有两个办法。一个是先在一台能联网的机器上执行脚本然后把脚本生成的gmp、mpfr、mpc三个目录连同源码一起拷进服务器。另一个是手动到GNU官方FTP或镜像站下载对应的压缩包GMP: https://ftp.gnu.org/gnu/gmp/MPFR: https://ftp.gnu.org/gnu/mpfr/MPC: https://ftp.gnu.org/gnu/mpc/下载完以后把压缩包直接放进GCC源码目录就行不需要手动解压。download_prerequisites脚本以及后续的configure逻辑能识别同目录下的这些tar.gz文件会自动处理。这个细节不少人不知道白解压了一回还容易因为目录名不一致造成依赖没被找到。压缩包的完整性校验不能省。我习惯在下载后做一次sha256sum比对因为镜像站偶尔会出问题损坏的依赖包会在configure阶段报出莫名其妙的语法错误排查起来非常浪费时间。2.3 内网服务器如何搬运依赖如果目标服务器完全离线我常用的操作是把整个构建环境做成一个压缩包一次拷贝到位# 在有网机器上 mkdir /tmp/gcc-build-env cd /tmp/gcc-build-env wget https://ftp.gnu.org/gnu/gcc/gcc-9.3.0/gcc-9.3.0.tar.gz wget https://ftp.gnu.org/gnu/gmp/gmp-6.1.0.tar.bz2 wget https://ftp.gnu.org/gnu/mpfr/mpfr-3.1.4.tar.gz wget https://ftp.gnu.org/gnu/mpc/mpc-1.0.3.tar.gz tar czf gcc-build-env.tar.gz *.tar.* # 把 gcc-build-env.tar.gz 拷进内网服务器到内网服务器上解压后把三个依赖压缩包移动或复制进gcc-9.3.0目录下再继续后续编译。整个过程只要依赖包版本匹配configure就不会在数学库环节卡住。3. 源码编译GCC 9.3的完整流程与参数选择3.1 分离构建目录别在源码目录里configureGCC编译有一个很多新手不知道的习惯绝对不要在gcc-9.3.0源码目录里直接执行configure。GCC属于多语言前端加大量生成代码的项目在源码目录内构建中间生成的文件会混进源码树以后想清理或重新配置很困难。标准做法是单独建一个构建目录mkdir -p /usr/local/src/gcc-build-9.3.0 cd /usr/local/src/gcc-build-9.3.0 ../gcc-9.3.0/configure --help先看--help确认自己系统里实际支持的参数再开始正式配置。这一步花不了两分钟但能避免参数拼写错误导致的反复失败。构建目录、源码目录、安装目录三者分离这是生产环境编译大型软件的基本原则。源码目录只负责存放原始代码构建目录放编译产物安装目录放最终可执行文件和库。以后想卸载直接处理安装目录和构建目录即可。3.2 configure参数逐项说明我这次使用的configure命令如下../gcc-9.3.0/configure \ --prefix/opt/gcc-9.3.0 \ --enable-languagesc,c \ --disable-multilib \ --disable-bootstrap \ --with-system-zlib各参数的意义和取舍如下参数作用我的推荐理由--prefix/opt/gcc-9.3.0指定安装目录放在/opt下不污染系统目录回滚时直接删目录--enable-languagesc,c选择要编译的语言前端只保留C和C省时间省磁盘--disable-multilib不编译32位版本服务器应用基本都是64位没必要支持32位--disable-bootstrap跳过三次自举校验赶时间用它不赶时间就去掉让GCC自举一轮更稳--with-system-zlib使用系统自带的zlib减少依赖树避免编译出多余静态库--disable-bootstrap值得单独解释一下。GCC默认会用刚编译出来的新编译器再编译一遍自己一共三轮叫bootstrap。这个机制能验证编译器是否自洽稳定性更好。代价是编译时间直接翻倍。如果服务器归你长期使用我建议不要禁用bootstrap如果只是临时构建环境、时间紧张加这个参数能省一个多小时。3.3 编译期间的并行度、内存与swap编译GCC最怕的不是CPU慢而是内存不够。8G内存的机器上直接make -j8往往编到一半就弹出internal compiler error: Killed (program cc1plus)这不是代码问题是内存被吃完了。我习惯按内存大小估算并发数每个并行编译任务至少预留1G到1.5G内存。比如8G内存保守用-j4最多-j6别再多了。磁盘空间也要留够整个构建过程大约需要5到8G空间先看一眼df -h。如果内存实在紧张可以临时开swapfallocate -l 8G /swapfile chmod 600 /swapfile mkswap /swapfile swapon /swapfileGCC 9.3编译耗时4核机器大概两三个小时16核机器三四十分钟。编译期间如果出现某个目标报错不要盲目重新跑make先看日志尾部通常错误信息会直接指出缺失的头文件、库或者内存问题。编译完以后执行安装make installmake install之后/opt/gcc-9.3.0目录下会有bin、lib、lib64、include等子目录工具链就算装好了。4. 环境变量配置与动态库冲突的配置陷阱4.1 PATH与LD_LIBRARY_PATH该配到什么位置GCC装好之后如果不配环境变量gcc --version显示的仍然是系统旧版本。要让新GCC优先生效需要把/opt/gcc-9.3.0/bin放到PATH最前面。但更关键的是动态库路径。你辛苦编完的程序运行时如果加载了系统旧的libstdc.so.6会直接报类似这样的错误./test: /usr/lib64/libstdc.so.6: version GLIBCXX_3.4.26 not found这里需要先确认实际库目录。GCC在64位x86上通常把库放在lib64但在某些ARM64发行版上可能是lib。所以别急着写死路径先查一下find /opt/gcc-9.3.0 -name libstdc.so*拿到实际路径后我习惯在/etc/profile.d/下新建一个环境变量脚本而不是去改/etc/profilecat /etc/profile.d/gcc93.sh EOF export PATH/opt/gcc-9.3.0/bin:$PATH export LD_LIBRARY_PATH/opt/gcc-9.3.0/lib64:/opt/gcc-9.3.0/lib:$LD_LIBRARY_PATH export MANPATH/opt/gcc-9.3.0/share/man:$MANPATH EOF source /etc/profile.d/gcc93.sh which gcc gcc --version放到/etc/profile.d/的好处是模块化。以后回滚删掉这一个文件登录环境就恢复原状不影响其他软件。这个文件只对新的登录会话生效当前SSH窗口需要手动source这是正常现象。4.2 ldconfig配置让非交互进程也能找到新库只配LD_LIBRARY_PATH有一个漏洞systemd服务、cron定时任务这类非交互环境通常不加载/etc/profile.d里的变量。你用新GCC编译的守护进程一旦交给systemd管理运行时就可能继续找不到新库。更稳妥的方案是把新库目录注册进ldconfigecho /opt/gcc-9.3.0/lib64 /etc/ld.so.conf.d/gcc-9.3.0.conf ldconfig ldconfig -p | grep libstdc这里要理解LD_LIBRARY_PATH和ldconfig的区别。LD_LIBRARY_PATH是当前进程环境变量对交互式Shell最直接ldconfig维护的是全局动态链接器缓存对所有不手动设置环境的进程生效。生产构建机上我通常两者都配确保命令行和后台服务都不踩库版本坑。但也别盲目在业务服务器上用ldconfig。新libstdc.so.6理论上向后兼容可是极少数老应用会依赖旧库的某种行为。如果这台机器上有跑了很多年的业务程序升级GCC前先在测试环境验证然后再决定是全局ldconfig还是只在构建用户的Shell环境里配LD_LIBRARY_PATH。4.3 验证当前生效的编译环境环境变量配好以后不能只看gcc --version那是表象。我一般做三步验证which gcc gcc --version g -dM -E -x c /dev/null | grep __cplusplus__cplusplus会告诉你编译器默认的C标准版本。GCC 9.3默认标准是C14输出201402L是正常的使用-stdc17时输出201703L。如果版本号显示正确基本可以确认PATH生效。还要验证动态库加载路径。编译一个最小程序再用ldd看它依赖的库到底落在哪里echo int main(){return 0;} /tmp/t.cpp g /tmp/t.cpp -o /tmp/t ldd /tmp/t | grep libstdc输出里如果显示libstdc.so.6 /opt/gcc-9.3.0/lib64/libstdc.so.6说明编译和运行时都走新库了。如果还指向/usr/lib64说明LD_LIBRARY_PATH没配好或者当前Shell没有重新加载环境变量。5. 升级后的验证、回滚与常见故障定位5.1 编译一个真实C程序确认链路完整最小程序毕竟太简单我习惯再用一个带C17特性的程序验证#include iostream #include map #include string int main() { std::mapint, std::string m; m[1] kylin; for (auto [key, value] : m) { std::cout key : value std::endl; } return 0; }编译运行g -stdc17 /tmp/test17.cpp -o /tmp/test17 /tmp/test17这段代码用了结构化绑定GCC 9.3编译完全没问题但如果还在旧GCC上C17支持是不完整的有些语法直接报错。这一步能验证编译器和运行时库整条链路。5.2 回滚策略一句话切换回旧GCC独立安装到/opt的好处在回滚时体现得最明显。要切回系统旧GCC只需要rm /etc/profile.d/gcc93.sh rm /etc/ld.so.conf.d/gcc-9.3.0.conf ldconfig新的登录会话就会恢复默认PATHgcc --version重新回到系统版本。不需要卸载/opt/gcc-9.3.0留着它将来要用再重新建一个/etc/profile.d/gcc93.sh文件就行。如果确认新版本以后完全不想用了彻底清掉rm -rf /opt/gcc-9.3.0 /usr/local/src/gcc-build-9.3.0这里要特别提醒不要为了“回滚”去动系统自带的gcc、g和/usr/lib64下的libstdc.so.6。那些属于系统组件能不动就不动。5.3 两个可复现的故障排查案例我在实际升级过程中遇到过两类问题都比较有代表性分享排查思路。第一个案例是systemd服务加载旧库。用新GCC编译了一个数据采集程序直接命令行启动没问题但注册成systemd服务后程序启动就报GLIBCXX_3.4.26 not found。原因就是systemd不读/etc/profile.d服务进程的环境里没有LD_LIBRARY_PATH。解决办法是在service里显式声明[Service] EnvironmentLD_LIBRARY_PATH/opt/gcc-9.3.0/lib64或者更省事在业务机、构建机上把新库目录加进ldconfig保证所有进程都能正确解析。但如果公司安全规范要求服务环境最小化就在每个unit文件里单独指定效果更可控。第二个案例是第三方库编译时仍然用了旧GCC。我先配好了环境变量直接命令行编译自己写的代码正常可后来编译某个开源库时发现它还是调用了/usr/bin/g。原因是很多构建系统在configure阶段会缓存CC和CXX变量或者项目脚本写死了编译器路径。解决方法是显式指定CC/opt/gcc-9.3.0/bin/gcc \ CXX/opt/gcc-9.3.0/bin/g \ cmake ..如果是Makefile项目执行make之前先看which gcc必要时用make CC/opt/gcc-9.3.0/bin/gcc CXX/opt/gcc-9.3.0/bin/g强制覆盖。这里把常见故障和排查思路整理成一张表方便遇到问题时快速对照故障现象可能原因解决思路GLIBCXX_3.4.2x not found程序运行时加载了系统旧libstdc配置LD_LIBRARY_PATH或ldconfiginternal compiler error: Killed (program cc1plus)内存不足降低make并行度扩展swapconfigure: error: Building GCC requires GMP...依赖缺失或版本不匹配把正确版本的依赖放进源码目录systemd服务启动报找不到新库systemd不加载/etc/profile.d在unit里设置Environment第三方库编译时仍用旧gccCC/CXX变量被写死或缓存显式指定CC和CXX环境变量6. 飞腾ARM服务器与运维层面的补充经验6.1 ARM64架构下的库目录差异飞腾、鲲鹏这类ARM64服务器上跑麒麟V10的场景越来越多GCC 9.3源码编译流程和x86基本一致但有几个差异值得注意。首先是库目录。x86_64上GCC的库普遍在lib64但一些基于Ubuntu改造的ARM64发行版上库会被放到lib或者lib/aarch64-linux-gnu。配置环境变量之前务必用find命令确认。直接写死lib64的人往往会在ldd验证阶段才发现路径不对白报一场错。其次是编译时长。ARM64服务器即使核心数很多编译GCC的整体耗时通常也比同级别x86机器慢。再加上内存占用特性不同更不建议盲目-j$(nproc)。我在飞腾机器上如果检测到内存不足会优先降并发而不是硬加swap因为闪存型存储上频繁swap对编译稳定性影响更大。最后如果项目对性能有极致要求编译业务代码时可以在ARM64上追加-mcpunative让编译器针对当前CPU微架构做优化。新GCC对ARMv8指令集的支持明显比旧版本强这本身也是升级GCC的重要收益。6.2 环境变更记录与可追溯性这次升级结束以后我顺手在/opt/gcc-9.3.0目录下放了一个README记录了四件事安装时间、源码包下载地址、configure参数、以及环境变量配置文件位置。这些信息看着琐碎但对生产环境来说非常关键。三个月后同事接手这台机器看到一个新目录如果没有任何说明大概率不知道是什么时候装的、为什么装的也不敢动。有了README后续维护、回滚、排查都能省下大量时间。无论怎么升级都要记得一个原则高版本GCC是给项目编译用的系统底层的旧GCC是给系统软件保平安用的。两者共存靠环境变量切换这才是国产化服务器上最稳妥的做法。

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

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

免费获取报价 →
↑