1. 项目背景与核心需求解析
1.1 为什么银河麒麟V10 SP3上装gcc-toolset-10会是个问题
先说结论:银河麒麟V10 SP3是基于Linux内核深度定制的国产服务器操作系统,兼容RHEL(Red Hat Enterprise Linux)系生态,很多开发者在上面编译C/C++项目时,第一反应是yum install gcc,但真到了需要C++17甚至C++20特性、需要更新工具链时,系统自带的gcc 4.8.5(RHEL系经典老版本)会卡得你怀疑人生。
gcc-toolset-10是RH(Red Hat)系发行版里通过SCL(Software Collections)软件集提供的一套较新的GCC 10编译工具链,包含了gcc、g++、gfortran等全套编译工具,而且能跟系统自带的旧版gcc共存,切换使用。对于需要在国产化平台做开发、适配、迁移的老哥们来说,这基本是绕不开的一个环节。
我在实际项目里遇到过从x86平台向ARM架构迁移的场景——银河麒麟V10 SP3同时支持x86_64和aarch64两种架构,很多编译坑都是架构差异和软件源差异叠在一起搞出来的。这篇博文就是基于实际踩坑经历,把“如何安全安装gcc-toolset-10”以及“yum仓库配置避坑”整理成一套可复现的流程,适合正在用银河麒麟做开发、做信创适配、或是在ARM环境里折腾工具链的同学参考。
1.2 核心需求拆解:装的不是一个包,是一条链路
安装gcc-toolset-10这个动作背后,实际上隐含了几个关键需求,搞清楚这些需求才能避免“装完了但用不了”的尴尬局面:
- 需求A:在不破坏系统自带gcc的前提下,提供新版编译能力。这是SCL的核心设计理念——老工具链可能被系统组件依赖,直接替换会出问题,SCL把新工具链隔离安装,使用时通过
scl enable切换。 - 需求B:搞定yum源,让依赖包能顺利下载。gcc-toolset-10并不是一个独立包,它依赖
devtoolset-10-runtime、gcc-toolset-10-binutils等一连串rpm包,yum源配置不对,后面全是依赖报错。 - 需求C:适配国产化平台的镜像源和架构差异。银河麒麟官方的源在某些内网环境下不可用,用的是镜像站,而镜像站上能跟银河麒麟匹配的软件集源需要仔细甄别——这是最容易踩坑的地方。
这三个需求环环相扣,下面逐步展开。
2. 环境梳理与方案选型:为什么用SCL而不是直接替换gcc
2.1 银河麒麟V10 SP3的系统特点和适配逻辑
银河麒麟V10 SP3的内核版本通常比较新(基于Linux 4.19或更新版本),但用户态工具链保持在相对保守的版本。这种配置是出于稳定性考虑——服务器操作系统不追求最新,只追求最稳。
但问题来了,如果你要编译一个使用了较新C++标准特性的开源项目(比如需要C++17的std::filesystem),系统自带的gcc 4.8.5根本过不了编译。这时候你有几种选择:
- 手动编译安装GCC 10源码包:耗时长、依赖链条复杂,在没有网的内网环境下更是灾难。
- 直接替换系统gcc为更高版本:可能导致glibc、动态链接库等系统组件异常,因为这些系统组件可能是按照旧gcc的ABI编译的。
- 使用SCL软件集(gcc-toolset-10):隔离安装,通过环境变量切换,不影响系统默认gcc,风险最小。
我选择的是方案3,这是RHEL系和麒麟系统上最稳妥的路径。SCL的原理说穿了很简单:把新工具链安装到独立的目录前缀下(通常类似/opt/rh/gcc-toolset-10/),然后通过环境变量设置(PATH、LD_LIBRARY_PATH、MANPATH等)让你“临时”切换到新工具链,切换只在当前shell会话中有效,不会全局污染。
2.2 各方案对比:选错方向,后面步步维艰
| 方案 | 安装复杂度 | 与系统兼容性 | 可维护性 | 推荐指数 |
|---|---|---|---|---|
| 手动编译GCC 10源码 | 高(需要30-60分钟编译,依赖不少) | 中偏高(需谨慎设置路径) | 较弱(卸载麻烦) | ★★★ |
| 直接替换系统gcc | 低 | 低(容易导致系统库ABI不兼容) | 极差 | ★ |
| SCL软件集gcc-toolset-10 | 低(yum源配好后一条命令) | 高(隔离安装、按需切换) | 强(可通过yum管理) | ★★★★★ |
这里面有一个很多人不理解的点:为什么SCL装了新gcc之后系统还是调用旧gcc?因为SCL的机制不是替换,而是“叠加”。scl enable gcc-toolset-10 bash这条命令执行后,会开启一个子shell,在这个子shell里PATH被前置了SCL的bin目录,于是gcc --version显示的是GCC 10;退出这个子shell,回到原环境,一切照旧。这种设计可以保证系统组件和自研代码互不干扰。
3. yum仓库配置避坑指南:镜像选择是第一个分水岭
3.1 银河麒麟V10 SP3到底该用哪个yum源
这是整个安装流程中最容易出问题的一步。银河麒麟V10 SP3的yum源配置有几种常见情况,我逐个说清楚:
情况一:系统自带的官方源(外网可访问)
如果你的服务器能正常访问外网,且系统自带的源文件没有被改动,理论上直接yum install gcc-toolset-10就能成功。但我实测发现,很多用户拿到手的系统镜像源地址过期或者DNS解析有问题,导致yum makecache卡死或报404。
检查方法:
cat /etc/os-release yum repolist如果yum repolist显示0个仓库,或者报错,说明源配置文件有问题,需要手动处理。
情况二:使用华为云、阿里云等公共镜像站
这里有一个关键窍门:银河麒麟V10 SP3自研版与RHEL 8的软件包兼容性较好,很多RHEL 8的第三方源可以“借用”,但“借用”也要讲究方法。华为云镜像站上有专门的Kylin目录和openEuler目录,其中openEuler 20.03 LTS的软件包与银河麒麟V10有较高兼容度,gcc-toolset-10在openEuler 20.03 LTS的软件源里是存在的。
以华为云镜像站为例,配置方式如下:
# 备份原repo文件,这是个好习惯 mkdir -p /etc/yum.repos.d/repo_backup mv /etc/yum.repos.d/*.repo /etc/yum.repos.d/repo_backup/ # 创建新的repo文件 cat > /etc/yum.repos.d/openEuler.repo << EOF [openEuler20.03] name=openEuler 20.03 LTS baseurl=https://mirrors.huaweicloud.com/openEuler/openEuler-20.03-LTS/$basearch/ enabled=1 gpgcheck=0 EOF但注意,不能让系统直接用openEuler的源替换掉麒麟的base源,gcc-toolset-10只是编译工具,很多基础依赖还是要从麒麟官方源获取。更稳妥的做法是:
cat > /etc/yum.repos.d/kylin-toolset.repo << EOF [gcc-toolset-10] name=openEuler 20.03 LTS Software Collections baseurl=https://mirrors.huaweicloud.com/openEuler/openEuler-20.03-LTS/$basearch/ enabled=1 gpgcheck=0 EOF这样只用一个专门的repo文件去上游源拉取gcc-toolset-10及其依赖,系统的基础包仍然走麒麟源,互不干扰。
提示:在写repo文件时,
$basearch变量会自动解析为x86_64或aarch64,无需手动修改,这能避免架构不匹配的问题。
3.2 内网离线环境的yum源搭建思路
实际生产中很多服务器在内网隔离环境,无法访问外网镜像。这种情况下需要在一台能上网的机器上先下载好所有相关rpm包,再传到内网部署。
下载rpm包的推荐方式:
# 在外网机器上配置好上面的repo源,然后执行 yum install --downloadonly --downloaddir=/tmp/gcc-toolset-rpms gcc-toolset-10如果--downloadonly插件没装,也可以用repotrack命令:
yum install -y yum-utils repotrack gcc-toolset-10 -p /tmp/gcc-toolset-rpmsrepotrack会把gcc-toolset-10及其所有依赖都拉下来,非常适合离网环境。拿到rpm包后,在内网服务器上:
yum localinstall /tmp/gcc-toolset-rpms/*.rpm或者将rpm目录做成本地yum源(用createrepo命令),方便多台机器共用。
3.3 yum源选择的关键判断标准
很多人会问:“我怎么知道这个源能不能用?”我的经验是三个判断维度:
- 架构匹配:查看
/etc/os-release或uname -i确认系统是x86_64还是aarch64,源地址里的架构标识必须匹配。 - 版本对应:银河麒麟V10对应RHEL 8.x的软件包体系,如果源里是RHEL 7风格的软件包,那sysroots和依赖库会有ABI不兼容问题。
- gcccheck设置:镜像站通常没有导入GPG密钥,配置repo文件时gpgcheck=0可以跳过签名校验,但在安全要求高的环境里,建议导入对应发行版的GPG密钥并保持gpgcheck=1。
我见过不少同事上来就复制网上流传的CentOS 7源直接覆盖,结果yum repolist倒是能出来了,但安装高版本gcc的时候直接报一串依赖错误,这就是源没选对导致的最典型故障。
4. 核心实操:gcc-toolset-10安装全流程详解
4.1 第一步:验证系统和网络准备情况
在动手之前,先把基础信息摸清楚。执行以下命令确认环境:
# 确认系统版本和架构 cat /etc/os-release uname -i # 确认yum源配置正常 yum repolist # 确认网络连通性(外网环境) curl -I https://mirrors.huaweicloud.com如果yum repolist报错或列表为空,先处理源的问题,不要急着进行下一步。这一步看似基础,但可以省掉后面80%的麻烦。
4.2 第二步:安装SCL相关基础组件
gcc-toolset-10依赖scldevel包集?准确说,安装gcc-toolset-10官方推荐先安装scl-utils,这是管理和启用软件集的工具包:
yum install -y scl-utils如果你的环境里连scl-utils都装不上,很可能是base源没配好。先在麒麟官方源或对应镜像源上把这个基础包装好。
4.3 第三步:正式安装gcc-toolset-10
这一步其实不需要额外安装centos-release-scl或者extras源,直接用前面配置好的gcc-toolset-10源的repo文件:
yum install -y gcc-toolset-10这里有个细节值得说一下——yum install gcc-toolset-10会同时安装gcc-toolset-10-gcc-c++、gcc-toolset-10-libstdc++-devel、gcc-toolset-10-gfortran、gcc-toolset-10-binutils等一系列相关包,这一点非常省心。但如果你只想装C编译器,不想要Fortran等额外组件,可以更精确地指定:
yum install -y gcc-toolset-10-gcc gcc-toolset-10-gcc-c++从文件系统角度来理解SCL的安装模式:所有文件被安装到/opt/rh/gcc-toolset-10/目录下(或/usr/local下,视具体发行版而定),包括可执行文件、库文件、头文件。这种“目录隔离”的模式,让卸载也变成一件简单事——直接yum remove对应包即可,不用担心残留问题。
4.4 第四步:环境切换与持久化配置
安装完成后,不要直接用gcc --version去验证,因为此时PATH还未指向新工具链。一定要用SCL提供的机制来启用:
# 方法一:在当前shell中临时启用(推荐用于测试) scl enable gcc-toolset-10 bash gcc --version # 方法二:直接在命令行中执行单条命令(不进入子shell) scl enable gcc-toolset-10 gcc --version如果看到输出是gcc (GCC) 10.3.1或类似版本号,说明安装成功。
对于希望将新工具链设为默认环境的用户,可以在~/.bashrc中追加以下内容:
source /opt/rh/gcc-toolset-10/enable但这个操作需要谨慎——它会全局影响你当前用户的编译行为。如果你同时在跑一个依赖旧gcc的构建脚本,建议仅在项目目录的.bashrc或构建脚本开头单独source。
4.5 第五步:验证编译功能(附带一个小测试)
快速写一个支持C++17特性的代码验证编译:
#include <iostream> #include <filesystem> int main() { std::filesystem::path p("./test_dir"); if (!std::filesystem::exists(p)) { std::filesystem::create_directory(p); } std::cout << "C++17 filesystem works! Path: " << std::filesystem::absolute(p) << std::endl; return 0; }编译运行:
scl enable gcc-toolset-10 bash g++ -std=c++17 test.cpp -o test ./test如果输出正常,说明文件系统库、C++标准库头文件、链接器等全套工具链都能正常工作。
4.6 安装完成后的目录结构和常用路径
了解SCL目录结构能帮你解决很多后续问题。安装完成后,重要文件路径如下:
| 路径 | 说明 |
|---|---|
/opt/rh/gcc-toolset-10/enable | 环境变量激活脚本 |
/opt/rh/gcc-toolset-10/root/usr/bin/gcc | gcc可执行文件 |
/opt/rh/gcc-toolset-10/root/usr/lib/gcc/... | 编译器内部库文件 |
/opt/rh/gcc-toolset-10/root/usr/include/ | 配套头文件路径 |
/usr/lib/gcc-toolset-10/lib或/opt/rh/.../lib | 运行时库路径 |
在配置CMake或Makefile时,经常需要指定CC和CXX变量:
export CC=/opt/rh/gcc-toolset-10/root/usr/bin/gcc export CXX=/opt/rh/gcc-toolset-10/root/usr/bin/g++或者更简单的方式,在cmake前面加scl enable:
scl enable gcc-toolset-10 cmake ..5. 多版本GCC共存管理与调试技巧
5.1 scl命令的进阶用法
gcc-toolset-10本身可以看成一个“软件集合”,当系统里同时存在多个软件集时,scl命令的enable参数可以叠加多个集合。比如:
scl enable gcc-toolset-10 llvm-toolset-10 bash这种多集合同时enable的能力在处理一些大型项目时非常有用——你可能同时需要新GCC和新的LLVM工具链。
但scl enable只在当前shell会话中生效,如果想查看当前shell中生效了哪些软件集,可以打印环境变量:
echo $PATH echo $LD_LIBRARY_PATH对比scl enable前后的输出,你能清楚看到PATH前缀的变化,这有助于理解SCL的隔离原理。
5.2 合并到现有编译环境的实操技巧
很多时候你不想每次编译前都手动执行scl enable,也不想把所有命令都塞进source脚本里。实际项目中,我通常会在项目的build脚本开头加一段:
source /opt/rh/gcc-toolset-10/enable export CC=/opt/rh/gcc-toolset-10/root/usr/bin/gcc export CXX=/opt/rh/gcc-toolset-10/root/usr/bin/g++这样做的好处是:构建时明确告知CMake或autotools系统使用哪个编译器,避免因PATH顺序问题误调用旧版gcc。
5.3 编译环境变量详解与答疑
SCL能工作的核心原理是几个环境变量的重定向,理解它们比死记命令更有价值:
- PATH:让
gcc、g++、ar、ld等二进制文件优先从新工具链目录中找到。 - LD_LIBRARY_PATH:让动态链接库搜索路径优先指向新工具链的库目录,避免链接到系统旧版libstdc++。
- MANPATH:让
man gcc查看的是手册是GCC 10的手册,而不是老版本的。
如果你在CMake或Makefile中遇到“linking C++ executable failed, cannot find -lstdc++”类的报错,常见的排查思路是确认LD_LIBRARY_PATH是否正确包含/opt/rh/gcc-toolset-10/root/usr/lib64目录。可以用echo $LD_LIBRARY_PATH检查。
另外一个高频问题是MPI环境。如果你需要搭配MPI进行并行编译,需要同时加载openmpi或mpich的SCL软件集,或者手动设置MPICC、MPICXX变量指向新工具链下的路径。这个细节在多节点HPC环境里尤其重要。
6. 常见问题与排查技巧实录
6.1 “没有可用软件包gcc-toolset-10”怎么办
这个问题是最常见的。引起它的原因主要有两个:
- repo源里确实没有这个包:openEuler 20.03 LTS的镜像源目录中,
gcc-toolset-10位于SoftwareCollections或PowerTools仓库里,如果没有启用对应的子仓库,yum是搜不到的。检查方式:
yum list available | grep -i gcc-toolset如果结果为空,尝试在repo文件中启用PowerTools或AppStream源:
# 在repo文件中添加 [appstream] name=AppStream baseurl=https://mirrors.huaweicloud.com/openEuler/openEuler-20.03-LTS/$basearch/ enabled=1 gpgcheck=0- 源地址配置错误:检查
baseurl是否包含了正确的架构目录和版本目录,尤其是aarch64环境,路径中$basearch建议写死成aarch64,避免变量解析错误。
6.2 yum安装时出现依赖冲突无法解决
这类报错通常表现为:
Error: Package: gcc-toolset-10-runtime-10.0-1.el8.x86_64 Requires: libtsan.so.2()(64bit)此时需要理清依赖关系链,常见的处理手法:
- 尝试更新系统基础包:
yum update -y,让系统的基础库版本对齐软件源中的要求。 - 添加额外的依赖源:gcc-toolset-10可能需要
glibc-devel、libgcc等系统包的较新版本,这些在麒麟官方源中可能版本较旧,可以尝试配置openEuler或RHEL 8兼容源来补齐。 - 检查架构是否混用:如果系统是aarch64架构,而repo源里匹配到了x86_64的包,就会出现“架构冲突”的报错。检查
uname -i,并在repo文件中写死正确的架构。
6.3 安装成功但gcc -v还是老版本
这个问题绝大多数时候是因为你忘了scl enable,直接敲了gcc --version。注意,SCL的enable操作不会全局生效,它只影响当前shell和由当前shell启动的子进程。解决方案在上文已给出:要么每次执行前先scl enable,要么在.bashrc中追加source脚本。
但还有另一种情况:你已经执行了scl enable,但gcc -v显示的仍是旧版本。这种情况通常是因为你的PATH环境变量中,其他目录排在了/opt/rh/gcc-toolset-10/root/usr/bin前面。检查一下echo $PATH,确认有没有其他自定义路径覆盖了SCL的路径。
6.4 ARM架构下的特殊问题
结合网络热词“银河麒麟服务器操作系统v10 sp3 iso arm”,aarch64架构下的安装确实与x86_64有些差异,最典型的有两个:
- repo源架构路径:华为云openEuler的aarch64软件源路径是
openEuler-20.03-LTS/aarch64/,如果配成了x86_64路径,虽然yum能列出仓库,但下载时会404。 - 部分编译依赖在ARM上没有构建版本:个别软件包在openEuler的ARM源中可能缺失,这种情况下可以考虑从RHEL 8 for ARM的兼容源中寻找,但要严格检查依赖的二进制兼容性。
6.5 安装源证书或GPG密钥问题
如果你配置的repo源开启了gpgcheck并且没有导入正确的GPG密钥,yum会拒绝安装并提示:
Public key for xxx.rpm is not installed解决方案有两种,一种是临时关闭gpgcheck(将repo文件中的gpgcheck改为0),另一种是导入发行版官方GPG密钥。对于镜像站环境,操作简便且安全性可接受的方案是直接gpgcheck=0,因为镜像站本身已经做了完整性校验。
7. 经验总结与后续扩展建议
7.1 安装思路的整体回顾
在银河麒麟V10 SP3上装gcc-toolset-10,本质上是“在兼容RHEL 8体系的国产系统上,用SCL机制引入新版工具链”的一个典型操作。整个过程最核心的节点就两个:yum仓库的选型和SCL机制的掌握。只要源配对了,安装不过是几条yum命令的事;只要理解了SCL的enable机制,环境切换就不容易翻车。
7.2 我的真实体会与额外建议
我踩过最有价值的一个坑,就是盲目复制网上的repo配置,结果架构对不上、版本对不上,最后在依赖地狱里挣扎了一整天。后来养成了一个习惯:动手装任何东西之前,先花5分钟把系统的发行版信息、架构信息、现有源列表全部确认一遍。这个习惯帮我省下的时间远超5分钟。
另一个经验是,不要一上来就用最新版本的工具链。gcc-toolset-10对于绝大多数项目来说已经足够新了,而且它经过RH和麒麟系的兼容性测试,稳定性有保障。如果一个项目对编译器的版本有特殊要求,再考虑gcc-toolset-11或12,迁移成本通常是可控的。
如果你后续要做CI/CD流水线,建议把“source /opt/rh/gcc-toolset-10/enable”操作固化到Docker镜像里,避免每次构建都切换环境。我就是这么做的,在基础镜像中提前安装好SCL工具集,然后统一在entrypoint里source,构建效率和稳定性都明显提升。