尧图网站设计 尧图网站设计YAOTU DESIGN
ARTICLE DETAIL

资讯详情

深耕网站设计与一线实操的经验洞察。

gcc_rpm.tar.gz离线安装与GCC升级切换实战指南

gcc_rpm.tar.gz离线安装与GCC升级切换实战指南 简介面向需要在无网络或内网环境下部署GCC编译环境的Linux运维与开发者这份离线RPM安装包提供了完整的GNU编译器集合及依赖组件可规避在线源不可用或依赖解析失败的问题适用于RHEL/CentOS 6 x86_64系统。压缩包共24个文件核心为22个rpm格式安装包覆盖编译器本体、C/C标准库、开发头文件等关键依赖另含1个shell自动安装脚本与1个Markdown说明文档便于一键执行与查阅步骤。包体整体约24MB结构紧凑便于拷贝至隔离环境使用。资源已有3988人学习适合需要快速为老旧或受限系统配置C/C编译工具链的开发者参考。通过该资源可掌握离线RPM方式安装GCC的完整依赖关系与安装流程并在断网条件下完成编译环境搭建。1. 先搞懂 gcc_rpm.tar.gz 是什么拿到gcc_rpm.tar.gz这个文件的时候第一反应多半是这到底是个 RPM 包还是个 tar 包其实两个都是——它是一堆 RPM 包被打成 tar.gz 归档后的产物常见于离线安装 GCC、批量部署编译环境或者从内网镜像站导出依赖包的场景。我在 CentOS 服务器上就经常收到这种文件里面通常包含 gcc 主程序、g、libgcc、libstdc、cpp、binutils 等一批关联 RPM甚至还有依赖链上的其他库。这篇文章就从gcc_rpm.tar.gz这个文件名出发聊聊怎么正确安装、升级和切换 GCC以及那些“升级后还是旧版本”“没有 rpm 命令”“CUDA 安装报错”之类的经典问题。如果你正在为离线环境装 GCC或者刚升级完发现系统没反应这篇文章应该能帮你少走不少弯路。1.1 一堆 rpm 为什么要打包成 tar.gz很多人第一次看到这种双重扩展名会觉得奇怪既然已经是rpm为什么不直接给一个目录或单独文件其实原因很简单。RPM 虽然是 Linux 上的标准安装包格式但它一装就是多个包依赖关系也很复杂。假如你需要在内网的一台机器上装 GCC把几十个 rpm 文件一个个传输太麻烦而且容易漏。打成一个 tar.gz既能用一条命令解压又保留了目录结构传输也更快。你可以先执行下面这条命令看看文件里有什么tar -tzf gcc_rpm.tar.gz输出里一般会列出gcc-9.4.0-1.el7.x86_64.rpm、gcc-c-9.4.0-1.el7.x86_64.rpm、libstdc-9.4.0-1.el7.x86_64.rpm之类的文件。这也就说明它本质上是一个“离线 yum 仓库”的迷你版里面的 rpm 包互相之间有依赖关系安装时最好按顺序或交给包管理器去解析。需要注意gcc_rpm.tar.gz不是源码包解压后不会出现configure脚本所以不要想当然地去执行./configure make。它里面的内容直接是二进制 rpm 包安装后即可使用。区分源码包和 rpm 归档的方法是看文件列表源码包里有.tar.xz、Makefile或configure.ac而 rpm 归档里全都是*.rpm。1.2 动手前先做环境检查别急着解压我在实际项目中见过不少同事拿到gcc_rpm.tar.gz后直接解压安装结果装到一半报依赖错误。其实在动手前花两分钟做个环境检查能避开大部分问题。你需要确认四件事系统发行版、当前 GCC 版本、是否安装了 rpm 命令、以及磁盘空间是否充足。cat /etc/redhat-release # 查看发行版 gcc --version # 当前 GCC 版本 which rpm # rpm 命令是否存在 df -h /opt # 确认安装目录磁盘空间如果系统是 CentOS/RHEL/Fedora通常自带 rpm但如果是 Ubuntu/WSL就没有 rpm 命令这时需要另想办法后面我会专门讲。另外GCC 的 rpm 包对底层库有依赖比如libmpc、mpfr、gmp如果系统版本太老缺少这些库安装时也会失败。可以用下面命令查看一个 rpm 包依赖哪些东西rpm -qpR gcc-9.4.0-1.el7.x86_64.rpm输出的依赖列表里如果有rpmlib开头的那是 rpm 自身的特性不用管如果有具体的库名比如libmpc.so.3()(64bit)就说明系统里必须存在这个动态库。如果缺依赖优先从系统安装盘或镜像站找到对应的 rpm 一起打包进来再重新生成一个新的gcc_rpm.tar.gz。2. RPM 包安装 GCC 实操从解压到正常使用检查完环境确认系统是 RHEL/CentOS 系列也准备好了 rpm 工具就可以开始安装了。这里我强烈建议不要一上来就rpm -ivh *.rpm因为 rpm 不处理依赖一旦包的安装顺序不对或者缺库就会直接报错。下面是我平时惯用的两种安装方式以及一个非常普遍的“升级后还是旧版本”问题。2.1 两种离线安装方式rpm -ivh 和 yum localinstall首先解压到指定目录mkdir -p /opt/gcc_rpm tar -xzf gcc_rpm.tar.gz -C /opt/gcc_rpm cd /opt/gcc_rpm接下来有两种选择。第一种是传统方式rpm -ivh *.rpm这种方式简单粗暴但不解决依赖顺序。如果 rpm 包自带互相依赖rpm -ivh *.rpm有时候也能成功因为 rpm 会先安装能被满足的包遇到依赖不足就中止。一旦中间有包因为某个依赖缺失而失败前面的包可能已经装上去了留下一个残缺状态。所以我更推荐第二种方式yum localinstall *.rpm -y如果是 CentOS 8 或更新的系统可以换成dnf install *.rpm -yyum localinstall会自动解析本地目录里的 rpm 包之间的依赖也会尝试从已配置的 yum 源中补足缺失的依赖。它在离线环境下尤其好用因为只要你的gcc_rpm.tar.gz打包时依赖收集得足够全它就能一路顺利装完。我把两种方式的区别整理成了表格方便你根据场景选择方式依赖处理适用场景缺点rpm -ivh *.rpm不处理遇到缺库直接报错依赖齐全、数量少安装顺序敏感容易半途失败yum localinstall *.rpm自动解析本地包间依赖也可从源补依赖离线包数量多、依赖复杂需要系统有 yum/dnf且本地包要完整rpm -Uvh *.rpm升级已有包时使用想让 GCC 替换系统旧版本同样不处理依赖依然有风险2.2 升级后还是旧版本PATH 和 alternatives 的坑这是被问得最多的一个问题“我明明升级了 gcc为什么gcc --version还是旧的”如果你也是用 rpm 包把 GCC 装到了自定义路径或者通过 Software Collections 安装了 devtoolset八成是 PATH 的优先级出了问题。RPM 安装 GCC 时通常会把二进制放到/usr/bin或/usr/local/bin。如果你在 CentOS 7 上装了 devtoolset-8 提供的 GCC 8.3.0二进制实际路径是/opt/rh/devtoolset-8/root/usr/bin/gcc而系统默认的/usr/bin/gcc还是 4.8.5。shell 查找命令时按照 PATH 从左到右找/usr/bin通常排在/opt/rh/devtoolset-8/root/usr/bin前面所以不管你怎么升级敲gcc永远是旧版本。解决办法有三个。临时切换export PATH/opt/rh/devtoolset-8/root/usr/bin:$PATH或者用update-alternatives管理默认版本update-alternatives --install /usr/bin/gcc gcc /opt/rh/devtoolset-8/root/usr/bin/gcc 100 update-alternatives --config gcc如果是源码编译后安装在/usr/local/bin同理把/usr/local/bin调整到 PATH 前面写入/etc/profile或当前用户的.bashrc。这里还要提醒一句不要只看gccg的版本也要一起确认因为很多项目同时依赖 gcc 和 g切换时只改了 gcc 而忘了 g编译 C 程序时还是会用旧版本产生一堆奇怪的报错。2.3 没有 rpm 命令的系统怎么处理这种包如果你的机器是 Ubuntu/Debian或者 WSL 默认 Ubuntu那么gcc_rpm.tar.gz解压出来的*.rpm是无法直接安装的。很多人第一反应是“那我装个 rpm 命令”确实可以执行sudo apt install rpm但我不建议你这么做因为 rpm 包即使是装上了也不会被 dpkg 跟踪后续卸载、升级都会很麻烦系统里一半 deb 一半 rpm简直是给自己埋雷。更合理的处理方式有两条。一条是用alien工具把 rpm 转成 debsudo apt install alien alien --to-deb *.rpm sudo dpkg -i *.deb但请注意alien转换时对一些复杂的依赖关系和系统脚本处理得并不完美尤其是 GCC 这种底层工具链转换后可能出现各种诡异问题。另一条更省事的思路是别在这个系统里死磕 rpm直接用 Ubuntu 自带的 apt 源装 GCCsudo apt update sudo apt install build-essential在 WSL 里搭建 GCC 开发环境我几乎只用这一条路。WSL 的 Linux 内核和 Ubuntu 软件源是完整可用的直接 apt 安装才符合系统习惯。只有在目标机器明确必须使用某个 rpm 包时我才会考虑让它跑一个 CentOS 容器作为编译环境而不是强行把 rpm 塞进 Ubuntu。3. GCC 升级路上的经典翻车现场升级编译器这件事很少有人能一次成功。很多时候错误信息并不会直接指向“GCC 版本不对”而是通过一个看起来无关紧要的报错把你引到编译器版本这条线上去。我在这一章里整理了三个最常见的翻车点每一个都有血泪教训。3.1 CUDA 与 NVIDIA 驱动安装时报 failed to verify gcc version如果你装过 NVIDIA 驱动或 CUDA大概率见过这句话failed to verify gcc version. see log at /var/log/cuda-installer.log for details这个报错的本质是CUDA 安装器会去检查当前系统的 GCC 版本是否在它支持的范围内。CUDA 对 GCC 的支持策略很保守比如 CUDA 11.4 支持的最高 GCC 是 10.x如果你的系统默认 GCC 是 11 或 12安装器就会拒绝继续反过来如果 GCC 版本太老也可能因为缺少某些新特性而失败。安装器还会调用 GCC 去编译一些测试代码所以它验证的不只是版本号还要求 GCC 真正可用。碰到这种情况先去看日志tail -n 100 /var/log/cuda-installer.log里面通常明确写了“expected gcc version between X and Y, but found Z”。然后在系统里找到支持范围内的 GCC并用环境变量或软链接让安装器使用正确版本。常见做法是export CC/usr/bin/gcc-9 export CXX/usr/bin/g-9 sudo ./cuda_installer.run或者驱动安装时有些版本支持这样指定sudo ./nvidia-linux-x86_64-550.100.run --no-opengl-files即便加了参数如果 GCC 本身版本不在支持列表里驱动安装器照样会校验失败。另外还有一个隐藏坑如果你此时已经升级过 GCC但内核模块编译用的是/usr/bin/gcc这个绝对路径而它指向的又是新版本那么即使安装器验证通过后续编译内核模块也可能失败。所以我现在的习惯是安装 CUDA 或 NVIDIA 驱动前先临时把系统gcc、g统一切换到安装器支持的版本装完再改回去。3.2 升级 GCC 后旧软件还能不能跑ABI 与 so 二进制兼容有人问“用 GCC 编出的 so 差异会大吗”。这个问题不能一概而论。如果是同一个 GCC 版本只是小补丁版本不同编出来的 so 基本没差别。但跨大版本比如从 GCC 4.8 升到 GCC 8.3差异就非常明显。GCC 5 是一个重要分水岭它改变了 C 标准库的 ABIstd::string、std::list等容器的底层实现变了。如果你用新 GCC 编译出来的 so 依赖了新版本 libstdc而可执行程序是用旧 GCC 编译的运行时很可能报GLIBCXX_3.4.21 not found之类的错误。换句话说新编译的 so 和旧程序不一定兼容。如果你的项目真的需要跨 ABI 场景可以用一个编译选项强制回到旧 ABIg -D_GLIBCXX_USE_CXX11_ABI0 -o mylib.so -shared mylib.cpp但这只是权宜之计。长期维护还是建议统一工具链版本所有模块用同一个 GCC 大版本重新编译。另外升级 GCC 后不要忘记 libstdc 动态库路径尤其是源码安装的 GCC默认库路径可能在/usr/local/lib64如果系统找不到需要设置LD_LIBRARY_PATH或更新/etc/ld.so.conf。3.3 编译时链接不到 SDL/第三方库和 GCC 版本有关吗网上经常有人问“gcc link sdl 失败”很多人误以为是升级 GCC 导致的。其实多数情况是开发包没安装或者 GCC 的搜索路径和库安装路径不一致。比如编译 SDL2 程序时gcc -o game game.c -lSDL2如果报错找不到头文件或库最常见的原因是缺少libsdl2-dev。这是头文件和链接下载文件的问题和 GCC 版本没有直接关系。但 GCC 升级后确实可能出现一个冷门问题源码编译的 GCC 安装在自定义 prefix 下默认的库搜索路径不包含/usr/local/lib或/usr/local/lib64这时候-lSDL2就算装了 SDL2 开发库也可能找不到。可以用下面命令查看 GCC 的搜索路径gcc -print-search-dirs如果发现库路径不对编译时手动指定即可gcc -o game game.c -I/usr/include/SDL2 -L/usr/lib/x86_64-linux-gnu -lSDL2 -lSDL2main这个问题的通用解决思路是先用pkg-config --cflags --libs sdl2查看正确的编译参数再把它放到命令行里而不是把锅甩给 GCC 版本。4. 特殊场景下的 GCC 安装思路并不是所有环境下都能轻轻松松用 rpm 装 GCC也并不是每个人都想让系统 GCC 被升级。这里分享几个我实际用过的特殊场景包括 conda 离线环境、WSL 开发环境以及嵌入式 IDE 里被 GCC 插件卡住的情况。4.1 用 conda 离线环境替代 rpm 方案tar.gz 也能创建 GCC 环境很多公司内网机器没有 root 权限或者你不希望动系统默认的/usr/bin/gcc这时 conda 是一个非常合适的隔离方案。有人会问conda 环境不都是基于 yaml 创建的吗其实 conda 本身也支持从本地压缩包创建环境。你可以在一台有网的机器上下载gcc_linux-64和g_linux-64的 conda 包通常是.conda或.tar.bz2格式然后把它们打包成 tar.gz带到内网去conda create --offline -n gcc-env /path/to/gcc_linux-64-*.conda /path/to/g_linux-64-*.conda创建成功后激活环境conda activate gcc-env gcc --version这种方法的好处非常明显环境完全隔离不会影响系统 GCC也不需要 root 权限想升级就重新创建一个环境。如果连 conda 源都没有更直接的方法是用 conda-pack 把已经配置好的环境打成 tar.gz在目标机器解压后 source activate里面就带了一套独立的 gcc 和 g。要注意的是conda 里的 gcc 名字可能带有前缀比如x86_64-conda-linux-gnu-cc编译代码时最好显式指定 CC 和 CXX。4.2 WSL 里搭建 GCC 开发环境别再硬找 rpm 命令WSL 是很多开发者的日常。在 WSL 里如果下载了一个gcc_rpm.tar.gz我建议直接把它扔到一边除非你确是在模拟 CentOS 环境。WSL 默认发行版如果是 Ubuntu安装 GCC 就一句话sudo apt update sudo apt install build-essential gdb装完后gcc --version就成了系统 GCC。如果你想在 VSCode 里写 C/C并直接用 WSL 里的 GCC 编译可以装一个 Remote-WSL 插件然后打开 WSL 目录底层调用的就是这个 GCC。还有不少做嵌入式开发的朋友会问如何把 STM32 工程在 VSCode 下使用 GCC 编译这里说的不是系统 GCC而是 ARM 交叉编译工具链。常用的arm-none-eabi-gcc在 Ubuntu 下同样可以用 apt 安装sudo apt install gcc-arm-none-eabi在 VSCode 里配置tasks.json把 command 指向arm-none-eabi-gcc再搭配 Cortex-Debug 插件烧录调试整套流程就通了。这个场景里完全没有 rpm 什么事如果你还在纠结gcc_rpm.tar.gz八成是找错方向了。4.3 嵌入式/IDE 场景从 STM32 到 S32 DSGCC 也能统一一些专业 IDE比如 S32 Design Studio 3.6会内置或要求外部的 GCC 工具链。最近有朋友遇到“安装插件 GCC 10.2 失败”的问题多半是它找不到指定版本的编译器或者系统默认 GCC 和插件要求的版本不一致。这种问题不建议去改系统 GCC因为系统级改动影响面太大。我采用的是“目录级工具链”方案把一个符合版本要求的工具链 tar.gz 解压到比如/opt/gcc-10.2然后在 IDE 的设置里把编译器路径指过去再把 PATH 按需添加。这样既不影响系统其他程序IDE 插件也能正确识别版本。对 STM32 来说arm-gnu-toolchain的 tar.gz 包解压即用也符合同样的思路。所以当你在 IDE 里遇到 GCC 版本校验失败时优先想“我能不能在外部准备一个独立版本”而不是推翻系统 GCC。5. 踩过这么多坑之后总结的几条实用经验写到这里我发现最终解决问题的往往不是某个具体命令而是做决策的思路。这一章我整理了几条个人经验希望能帮你少踩点坑。5.1 什么时候该用 rpm 包什么时候干脆源码编译如果目标是 CentOS 7 上把 GCC 升级到 8.3.0且机器能访问内网 yum 源优先使用 SCL 或 RPM 包因为快、可回滚、管理方便。但如果你需要的是一个自定义配置的 GCC比如只编译 C 和 C或者需要关闭 multilib源码编译更合适。源码编译 GCC 是件非常消耗时间的事情有点耐心的话一个 8.3.0 干净编译至少需要三四十分钟机器配置差可能要一小时以上。configure 参数也很有讲究不同选项会影响最终安装路径和功能比如./configure --prefix/usr/local/gcc-8.3.0 --enable-languagesc,c --disable-multilib make -j$(nproc) sudo make install如果你是首次编译建议先configure --help看看有哪些选项。我用源码编译后系统里往往会出现/usr/local/bin/gcc和/usr/bin/gcc并存这又回到了 PATH 和 alternatives 的问题。所以不到万不得已我还是优先推荐用 rpm 或 conda省心很多。5.2 升级 GCC 后必查的三项验证升级完 GCC很多朋友敲一句gcc --version看到新版本就以为大功告成。实际上至少要做三项检查缺一不可。第一确认gcc和g都指向新版本which gcc g gcc --version g --version第二检查 PATH 的顺序确保新版本路径排前面echo $PATH第三检查 C 运行库版本是否匹配。如果你的程序链接了 libstdc用这个命令查看strings /usr/lib64/libstdc.so.6 | grep GLIBCXX对照你程序运行所提示的 GLIBCXX 版本号如果系统 libstdc.so.6 里的版本比程序要求的低升级就没彻底。该重新生成软链接就重新生成该更新 ldconfig 就更新。另外改完 PATH 或 alternatives 后一定要重新登录或者source ~/.bashrc否则当前终端还是旧环境。5.3 RPM 查询和依赖定位技巧最后一个实用技巧是关于 RPM 查询的尤其是离线环境里排查依赖的时候。常用几个命令是rpm -qa | grep gcc # 模糊查询已安装的 gcc 相关包 rpm -qf /usr/bin/gcc # 查看某个文件属于哪个包 rpm -qpR gcc-9.4.0-1.el7.x86_64.rpm # 查看未安装的 rpm 包依赖 rpm -qpi gcc-9.4.0-1.el7.x86_64.rpm # 查看未安装包的信息 yum provides */gcc # 在 yum 源中搜索命令对应的包如果你拿到一个gcc_rpm.tar.gz却发现安装时报缺依赖其实不必惊慌。先rpm -qpR把缺的依赖名记下来去系统安装光盘的Packages目录或内网镜像里找到对应 rpm下载后补进同一个目录再重新打包成 tar.gz下次就可以直接交给别人了。很多gcc_rpm.tar.gz文件就是这么来的——上一个安装的人已经踩过一遍依赖坑再分发时就帮你把配套的包全放一起了。这几年我处理过好几次离线 GCC 安装最大的感受是文件本身并不复杂复杂的是系统里已经存在的旧工具链和各种依赖约束。不要急着解压安装先想清楚你要哪个版本、装到哪里、会不会影响现有程序再动手。最后再提醒一句任何升级前最好先备份一下/usr/bin/gcc和/usr/lib64/libstdc.so.6万一出问题还能快速回滚。本文还有配套的精品资源点击获取
返回列表