第3章:编译器与工具链:GCC 源码安装

编译器是把 C++ 源码翻译成机器码的"翻译官";当系统自带的翻译官太老、听不懂新标准时,你需要亲手从源码再培养一位

🏛️

本章导师:狄仁杰

核心方法论:系统分析

「断案如拆机。再离奇的案子,也不过是案发、取证、推理、定案几个环节——总有一环出了岔子。GCC 装不上也是一样:下载、依赖、配置、编译、安装,五个环节里必有一环出了问题。我不信巧合,只信把每个环节单独拎出来查个水落石出。这一章,随我把这条链路一节一节拆开看。」

3.1 零基础铺垫:GCC 是什么:把 C++ 翻译成机器码的编译器家族

先回答一个最基本的问题:什么是编译器(compiler)?说人话,编译器就是一个"翻译官"——把人类能读懂的源码(比如 C++)翻译成 CPU 能直接执行的机器码。第 1 章讲过,C++ 是编译型语言:写好的 .cpp 文件必须先经过编译,生成可执行文件,才能运行。而这个"翻译"动作的执行者,就是本章的主角 GCC

GCC 全称 GNU Compiler Collection(GNU 编译器集合),是 GNU 项目(GNU 是 "GNU's Not Unix" 的递归缩写,一个致力于自由软件的操作系统项目)的核心成果之一,由自由软件基金会(FSF)维护,1987 年发布第一个版本。它最初只支持 C 语言,名字叫 GNU C Compiler,后来逐渐加入 C++、Fortran、Go、Ada 等多种语言的支持,名字也随之改成了"编译器集合"。你常用的 gccg++,其实都是这一个编译器家族的成员:gcc 按 C 语言规则编译 .c 文件,g++ 按 C++ 规则编译 .cpp 文件,并且链接时会自动带上 C++ 标准库 libstdc++。

用系统分析的方法看,一个编译器的内部可以分成三段流水线:前端负责"读源码"——做词法、语法分析,把源码变成一种统一的中间表示(GCC 里叫 GIMPLE);中端负责"做优化"——在中间表示上做各种优化(死代码消除、内联、循环优化等),这部分与具体语言和硬件都无关;后端负责"生成机器码"——把优化后的中间表示翻译成某个 CPU 架构的汇编。正因为三段分离,GCC 才能做到"多种语言前端 + 多种架构后端"的排列组合:加一种新语言只写前端,支持一种新 CPU 只写后端。

命令角色说人话
gccC 语言前端驱动编译 C 源码
g++C++ 语言前端驱动编译 C++ 源码,链接时自动带 libstdc++
gfortranFortran 前端驱动编译 Fortran 源码
as / ld汇编器 / 链接器来自 binutils 包,负责汇编与链接
libstdc++C++ 标准库C++ 程序运行时要依赖的标准库实现

为什么你通常感觉不到"工具链"的存在?因为 g++ 一条命令把预处理、编译、汇编、链接四步全包了。但搞清楚这几步,是后面排查一切编译问题的前提——报错发生在哪一步,问题就出在哪一类东西上。

# 用 g++ 编译 C++ 程序:一条命令完成 预处理→编译→汇编→链接
g++ hello.cpp -o hello

# 用 gcc 也能编译 C++ 文件,但链接时必须手动加 -lstdc++
gcc hello.cpp -o hello -lstdc++
# 查看 GCC 家族成员版本(-v 会打印完整的编译配置与版本号)
gcc --version
g++ --version

# 工具链的其他成员来自 binutils 包
as --version
ld --version
狄仁杰提示

想亲眼看看"一条 g++ 命令背后发生了什么",执行 g++ -v hello.cpp -o hello——它会把调用的 cc1plus(编译器本体)、as(汇编器)、collect2/ld(链接器)一行行打印出来。这就是系统分析的起点:先看清环节,再谈定位问题

3.2 GCC 版本与 C++ 标准支持对照

C++ 不是一成不变的语言,它由 ISO 标准化组织维护,标准编号为 ISO/IEC 14882,大约每三年发布一个新版本:C++98(1998 年)、C++11(2011 年)、C++14(2014 年)、C++17(2017 年)、C++20(2020 年)。每发布一个新标准,编译器都要花上几年才能把它完整实现——所以"编译器版本够不够新"直接决定了你能不能用上新语法

GCC 对 C++ 各标准的支持进度,记住下面四个里程碑就够用了:GCC 4.8(2013 年)起完整支持 C++11GCC 5.1(2015 年)是首个完整支持 C++14 语言特性的版本;GCC 7(2017 年)引入 C++17(GCC 8 补全剩余特性);GCC 10(2020 年)提供 -std=c++20 选项,支持 C++20 的大部分特性。还有一个容易踩的坑:默认模式永远落后于最新标准——GCC 5 的默认模式仍是 gnu++98,GCC 6 起默认 gnu++14,直到 GCC 11 才把默认改为 gnu++17。也就是说,就算你装的是新 GCC,不写 -std= 选项,它也只会按旧标准编译你的代码。

GCC 版本发布年完整支持的标准开启选项
GCC 4.8.12013C++11-std=c++11
GCC 5.12015C++14-std=c++14
GCC 72017C++17-std=c++17
GCC 102020C++20(大部分)-std=c++20
# 编译时用 -std= 显式指定标准(gnu++14 表示"带 GNU 扩展的 C++14")
g++ -std=c++14 hello.cpp -o hello
g++ -std=c++17 hello.cpp -o hello
g++ -std=c++20 hello.cpp -o hello

# 看看当前 GCC 默认按什么标准编译(GCC 5 默认 gnu++98)
g++ -dumpspecs | grep -o "std=gnu++[0-9]*" | head -1
// __cplusplus 宏:编译期告诉你当前按哪个标准编译
#include <iostream>

int main() {
    // C++11 输出 201103L,C++14 输出 201402L,C++17 输出 201703L
    std::cout << __cplusplus << std::endl;
    return 0;
}

日常排查时记住一句口诀:看到新语法报语法错误,先查两件事——编译器版本够不够新、-std= 有没有写对。比如在 GCC 4.8 上编译 C++14 代码,会直接报 cc1plus: error: unrecognized command line option '-std=c++14'——问题一目了然:不是代码错了,是"翻译官"太老。

注意:判断"我的 GCC 支持哪个标准",权威依据是 gcc.gnu.org 上每个版本的发布说明(Release Series Changes)和 libstdc++ 的标准支持状态页。网上流传的"版本号对照表"偶尔会有偏差,涉及关键决策时以官网为准。

3.3 为什么有时必须源码安装

大多数 Linux 发行版都自带 GCC,直接 sudo yum install gcc gcc-c++sudo apt install build-essential 就能用。但系统自带的编译器有一个先天局限:版本由发行版决定,且普遍偏旧。CentOS 7 自带的是 GCC 4.8.5(只完整支持 C++11),Ubuntu 16.04 自带 GCC 5.4;而不少第三方库为了提高性能、简化代码,都要求较新的编译器——比如 POCO 这类现代 C++ 库,新版本就明确要求支持 C++14 甚至 C++17 的编译器。这就是本章素材记录的原始动机:"对于一些源码的编译如 poco 库,需要的 GCC 的版本要求比较高,所以需要源码编译 GCC"。

什么时候必须走源码安装?三种典型场景:第一,要用新标准——发行版只提供老编译器,而你的项目想用 C++17/C++20;第二,要特定版本——某个库或工具链要求精确的 GCC 版本(编译器版本影响 ABI 兼容性,混用不同版本编译的库可能链接失败);第三,发行版仓库里根本没有——某些精简系统或特殊发行版不提供 GCC 包。相比之下,用 apt/yum 装的是发行版"定制过"的版本,胜在快、有依赖管理,但版本选择几乎没有余地。

维度包管理器安装(apt/yum)源码安装
版本选择发行版打包的固定版本任意版本,精确可控
安装位置系统目录(/usr/bin)--prefix 自定义(如 /usr/local 或 /opt/gcc-5.1.0)
耗时几分钟编译几十分钟到几小时
升级维护包管理器自动处理自己重新编译安装
适合场景日常开发、无版本要求新标准、特定版本、多版本共存
# 看看系统自带的 GCC 是哪个版本(CentOS 7 上是 4.8.5)
gcc --version
# gcc (GCC) 4.8.5 20150623 (Red Hat 4.8.5-44)

# 想用 C++14?老编译器直接拒绝:
g++ -std=c++14 test.cpp
# cc1plus: error: unrecognized command line option '-std=c++14'
# 源码安装 GCC 前,先确认"能编译编译器的编译器"存在(自举 bootstrap)
gcc --version          # 需要一套可用的工具链来编译新 GCC
make --version         # GNU make
bison --version        # 生成语法分析器(可选但建议)

# CentOS / RHEL 上一次性装齐基础开发工具
sudo yum groupinstall "Development Tools"
狄仁杰提示

源码安装 GCC 有个著名的"鸡生蛋"问题:编译 GCC 需要编译器。解法是自举(bootstrap)——先用系统里已有的老 GCC 把新 GCC 的 C 部分编译出来(第一阶段),再用这个新编译器把新 GCC 完整地再编译一遍(第二阶段)。所以系统里有一个能用的 gcc 是前提,哪怕它很老。第 4 章我们还会见到不编译源码、直接用 devtoolset/SCL 切换 GCC 版本的方案。

3.4 第一步:下载源码与准备依赖

GCC 的所有版本都发布在 GNU 官方 FTP 上:https://ftp.gnu.org/gnu/gcc/(入口页是 gcc.gnu.org 的 Releases 页面)。国内网络访问 ftp.gnu.org 可能较慢,可以改用清华 TUNA 镜像 https://mirrors.tuna.tsinghua.edu.cn/gnu/gcc/,文件内容完全一致。本章素材下载的是 gcc-5.1.0——这是首个完整支持 C++14 的版本,2020 年那会儿用它来编译对 C++14 有要求的 POCO 库正合适。

源码解压后先别急着 configure,GCC 编译自己需要三个数学库:GMP(GNU Multiple Precision Arithmetic Library,任意精度整数/有理数运算库)、MPFR(基于 GMP 的多精度浮点运算库,保证正确舍入)、MPC(基于 GMP 和 MPFR 的复数运算库)。GCC 的前端在编译期做高精度常量运算(比如折叠 constexpr 浮点表达式)时会用到它们。GCC 5.1 对版本的要求是:GMP 4.2+、MPFR 2.4.0+、MPC 0.8.0+——不满足时 configure 会直接报错。

# 从 GNU 官方 FTP 下载并解压(国内可换 TUNA 镜像,见上方提示)
wget https://ftp.gnu.org/gnu/gcc/gcc-5.1.0/gcc-5.1.0.tar.bz2
tar xjf gcc-5.1.0.tar.bz2
cd gcc-5.1.0

最简单的依赖准备方式,是运行源码树里自带的脚本 ./contrib/download_prerequisites——它自动从 ftp://gcc.gnu.org/pub/gcc/infrastructure/ 下载 GCC 官方测试过的依赖版本(在 5.1.0 里是 gmp-4.3.2、mpfr-2.4.2、mpc-0.8.1,以及用于 Graphite 循环优化的 isl-0.14),解压到源码树内并创建 gmpmpfrmpc 软链接,顶层 configure 会自动识别它们,无需手动安装到系统。

# 一键下载并安放全部依赖(素材中的真实命令,在源码目录内执行)
./contrib/download_prerequisites

# 脚本会创建如下软链接,configure 阶段自动识别:
# gmp -> gmp-4.3.2   mpfr -> mpfr-2.4.2   mpc -> mpc-0.8.1

如果不想用脚本,也可以手动下载更新的依赖版本、逐个编译安装(素材里就是这么做的,用的是当时较新的 gmp-6.1.0 / mpfr-3.1.4 / mpc-1.0.3,默认安装到 /usr/local):

# 备选方案:手动下载依赖(官方基础设施目录)
wget ftp://gcc.gnu.org/pub/gcc/infrastructure/gmp-6.1.0.tar.bz2
wget ftp://gcc.gnu.org/pub/gcc/infrastructure/mpfr-3.1.4.tar.bz2
wget ftp://gcc.gnu.org/pub/gcc/infrastructure/mpc-1.0.3.tar.gz

# 依次解压、configure、编译、安装(先 gmp,再 mpfr,最后 mpc)
tar xjf gmp-6.1.0.tar.bz2
cd gmp-6.1.0
./configure
make && sudo make install
cd ..

# mpfr、mpc 同样操作,顺序不能乱:mpc 依赖 gmp 和 mpfr

注意:手动编译 gmp 时如果报 error: No usable m4 in $PATH or /usr/5bin,说明系统缺 m4(一个宏处理工具),装上即可:sudo yum install m4(Debian/Ubuntu 用 sudo apt install m4)。这是素材里真实遇到过的坑。

狄仁杰提示

还有第三条路:直接用系统的包管理器装依赖开发包——CentOS 上 yum install gmp-devel mpfr-devel libmpc-devel,Ubuntu 上 apt install libgmp-dev libmpfr-dev libmpc-dev。装到系统路径后,GCC 的 configure 也能找到它们。缺点是这个方案依赖系统仓库里这些库的版本够新,CentOS 7 仓库里的版本就偏旧,所以素材里才选了手动编译较新版本。

3.5 第二步:configure:探测环境、生成构建配置

configure 是一个由 autoconf 工具生成的可执行脚本(几乎所有 GNU 软件的源码树里都有),它的职责是探测当前系统的环境:有没有可用的编译器、各依赖库装在哪、头文件在不在、CPU 是什么架构,然后把结果写进生成的 Makefileconfig.h。换句话说,configure 负责回答"这台机器上怎么编译",make 负责回答"按这个方案编译"。同一个源码包,在千奇百怪的 Linux 环境里都能编译成功,靠的就是这一层探测。

GCC 的 configure 参数很多,日常够用的就这几个:--prefix 指定安装目录(默认 /usr/local,多版本共存时改成 /opt/gcc-5.1.0 之类的独立目录);--enable-languages=c,c++ 只编译 C 和 C++ 两个前端(默认会编全部语言,白白多花几十分钟);--enable-checking=release 控制编译器内部一致性检查的强度(release 是性能与安全之间的折中,默认是 yes);--disable-multilib 禁止生成 32 位变体——64 位系统上如果没装 32 位库,多库支持会导致链接阶段报错,直接关掉最省心。

# 素材中的真实配置命令(在 gcc-5.1.0 源码目录内执行)
./configure --enable-checking=release --enable-languages=c,c++ --disable-multilib
# 多版本共存时,用 --prefix 把新 GCC 装到独立目录
./configure --prefix=/opt/gcc-5.1.0 \
    --enable-languages=c,c++ \
    --enable-checking=release \
    --disable-multilib

# 依赖装到非标准位置时,用 --with-* 指明路径(按需)
# ./configure --with-gmp=/usr/local --with-mpfr=/usr/local --with-mpc=/usr/local

还有一个推荐做法:out-of-tree 构建——在源码目录外单独建一个 build 目录,从那里调用源码树里的 configure。这样编译产生的海量中间文件全部落在 build 目录里,源码目录始终保持干净,想重来就删掉 build 目录,源码毫发无损。

# 推荐:源码目录外构建(用 ../configure 引用源码树)
mkdir build
cd build
../configure --enable-checking=release --enable-languages=c,c++ --disable-multilib

注意:configure 阶段最常见的报错是依赖缺失——如果看到 error: Building GCC requires GMP 4.2+, MPFR 2.4.0+ and MPC 0.8.0+configure: error: gmp.h not found,说明依赖三件套还没就绪。回到 3.4 节把 ./contrib/download_prerequisites 跑一遍即可。记住狄仁杰的排查法:报错出现的位置 = 出问题的环节,configure 阶段报错,问题几乎都在依赖。

3.6 第三步:编译、安装与验证

configure 顺利通过后,真正的重头戏来了。make 默认是单线程编译,GCC 这种体量的项目会慢到怀疑人生,所以一定要并行:make -j$(nproc)(nproc 输出 CPU 核数,让编译任务铺满所有核)。默认配置下 make 会执行三阶段自举:第一阶段用系统老编译器编译出新 GCC;第二阶段用这个新 GCC 重新编译自己;第三阶段再编译一次并与第二阶段的结果比对,确保编译器"自我一致"。整个过程在八核机器上通常要 30 分钟到 1 小时以上,期间风扇狂转是正常现象。

编译完成后 make install 把产物安装到 --prefix 指定的目录(默认 /usr/local):可执行文件进 /usr/local/bin(gcc、g++、gfortran 等),库文件进 /usr/local/lib64(libstdc++.so.6 就在这里),C++ 标准库头文件进 /usr/local/include/c++/5.1.0。安装完成后用 gcc -vgcc --version 验证版本——素材里的真实输出是 gcc version 5.1.0 (GCC)

# 并行编译:-j 后面跟并行任务数,$(nproc) 自动取 CPU 核数
make -j$(nproc)

# 编译通过后安装(默认装到 /usr/local,需 root 权限)
sudo make install
# 验证版本(素材中的真实输出)
gcc -v
# gcc version 5.1.0 (GCC)
gcc --version
# gcc (GCC) 5.1.0
g++ --version

# 小实验:编译一个需要 C++14 的程序,确认新编译器真的能用
g++ -std=c++14 hello.cpp -o hello && ./hello

验证通过,但还有最后一道坎:新编译器的库,系统找不找得到。新 GCC 的 libstdc++ 装在 /usr/local/lib64,而系统里其他程序(以及后续编译出的程序)默认去 /usr/lib64 找库——版本对不上时,运行程序会报 libstdc++.so.6: version 'GLIBCXX_3.4.21' not found。素材里的处理办法是把新库复制到系统库目录(需要 root):

# 素材中的真实处理:把新 libstdc++ 复制到系统库目录
cp -vf /usr/local/lib64/libstdc++.* /usr/lib64/

# 不想动系统目录的话,用环境变量指路(仅对当前 shell 生效)
export LD_LIBRARY_PATH=/usr/local/lib64:$LD_LIBRARY_PATH
狄仁杰提示

make 阶段报错也别慌,先看错误信息里"缺什么"。缺头文件(如 gmp.h: No such file)说明依赖没就绪;缺工具(如 m4、bison)就装工具;报 internal compiler error 且发生在优化环节,往往是内存不足或磁盘写满。每一步报错都对应一个明确环节——这就是系统分析的价值。

3.7 常见坑与多版本共存

把源码安装整条链路跑通之后,还有一批高频问题值得提前打预防针。下面这张表汇总了最常见的报错、原因和解决方向——建议收藏,遇到问题先对号入座,再动手。

报错现象原因解决
configure: error: gmp.h not found / Building GCC requires GMP…GMP/MPFR/MPC 依赖未就绪./contrib/download_prerequisites 或装 dev 包
error: No usable m4 in $PATH or /usr/5bin系统缺 m4 宏处理工具yum install m4 / apt install m4
libstdc++.so.6: version 'GLIBCXX_3.4.21' not found运行时用了系统旧版 libstdc++复制新库到 /usr/lib64 或设置 LD_LIBRARY_PATH
/usr/bin/ld: cannot find -lstdc++链接器没找到新标准库确认安装路径,必要时加 -L/usr/local/lib64
make 中途被 kill / internal compiler error内存或磁盘不足降低 -j 并行度,清理磁盘空间

第二个高频主题是多版本共存。生产环境里常见的诉求是"系统默认 GCC 不动,新 GCC 供特定项目用"。做法很简单:新版本用 --prefix=/opt/gcc-5.1.0 装到独立目录,然后通过 PATH 环境变量控制"哪个 gcc 生效"。PATH 是 shell 查找命令时依次扫描的目录列表,排在前面的目录优先——把新 GCC 的 bin 目录放在 PATH 最前面,gcc 就指向新版本;去掉它,又回到系统版本。改完 PATH 记得 hash -r 清除 shell 的命令路径缓存,并用 which gcc 确认当前生效的是谁。

# 把新 GCC 放到 PATH 最前面(当前 shell 立即生效)
export PATH=/opt/gcc-5.1.0/bin:$PATH

# 确认当前生效的 gcc 到底是哪个(输出 /opt/gcc-5.1.0/bin/gcc)
which gcc

# 写进 ~/.bashrc 永久生效,然后刷新;hash -r 清除旧路径缓存
echo 'export PATH=/opt/gcc-5.1.0/bin:$PATH' >> ~/.bashrc
source ~/.bashrc
hash -r
# 排查"新 gcc 编译的程序跑不起来"的完整流程
# 1. 看可执行文件依赖了哪些动态库
ldd ./app | grep stdc++
#   libstdc++.so.6 => /usr/lib64/libstdc++.so.6  ← 找到旧库了

# 2. 确认新库的版本符号是否满足要求
strings /usr/local/lib64/libstdc++.so.6 | grep GLIBCXX_3.4.21

# 3. 让运行时找到新库(二选一):复制到系统目录,或设 LD_LIBRARY_PATH
export LD_LIBRARY_PATH=/usr/local/lib64:$LD_LIBRARY_PATH

最后一个提醒关于 ABI 兼容性(ABI 是 Application Binary Interface,说人话就是"编译好的二进制之间互相调用的约定")。GCC 5 起 libstdc++ 默认启用新的 C++11 ABI(可用宏 _GLIBCXX_USE_CXX11_ABI 查看,默认值为 1),这是 GCC 5 发布说明里明确标注的重大变更:用新编译器编译的库和用老编译器编译的库,std::string 等类型的内部布局不同,混链可能出问题。如果你的项目要链接一批用老 ABI 编译的第三方库,可以给新编译加 -D_GLIBCXX_USE_CXX11_ABI=0 切回旧 ABI——但整个项目的所有编译单元必须保持一致。

# 查看当前编译器默认的 ABI 模式(1 = 新 C++11 ABI,0 = 旧 ABI)
g++ -dM -E -x c++ /dev/null | grep _GLIBCXX_USE_CXX11_ABI
# #define _GLIBCXX_USE_CXX11_ABI 1

# 需要兼容旧 ABI 库时,统一加这个宏再编译
g++ -std=c++14 -D_GLIBCXX_USE_CXX11_ABI=0 app.cpp -o app
狄仁杰提示

回顾本章的排查心法:把链路拆成环节,报错在哪环,问题就在哪环——下载失败看网络与镜像,configure 报错看依赖,make 报错看工具与资源,运行报错看库路径与 ABI。GCC 源码安装看似步骤多,其实每个环节都能独立验证,这正是系统分析最典型的用法。下一章我们继续沿用这套方法,讲环境变量与多版本 GCC 的切换管理。

章末练习

练习 1:概念三连 入门

用一句话分别解释:编译器GCCgcc 与 g++ 的区别。再回答:为什么 GCC 5.1 已经支持 C++14,编译时还得写 -std=c++14

提示

想想 3.1 的"翻译官"比喻、3.2 的"默认模式永远落后"这个坑。

参考答案

编译器:把源码翻译成机器码的程序;GCC:GNU Compiler Collection,GNU 项目的多语言编译器家族;gcc 按 C 规则编译 .c 文件,g++ 按 C++ 规则编译 .cpp 文件并自动链接 libstdc++。因为 GCC 5 的默认模式仍是 gnu++98,新标准必须用 -std=c++14 显式开启(GCC 6 起默认 gnu++14,GCC 11 起默认 gnu++17)。

练习 2:命令配对 入门

把"下载 / 依赖准备 / 环境探测 / 编译 / 安装 / 验证"六个环节分别对应到一条命令(或一组命令):make./configure ...wget https://ftp.gnu.org/gnu/gcc/gcc-5.1.0/gcc-5.1.0.tar.bz2./contrib/download_prerequisitesmake installgcc -v

提示

按 3.4 → 3.5 → 3.6 的顺序走一遍就出来了。

参考答案

下载:wget ...gcc-5.1.0.tar.bz2 + tar xjf;依赖准备:./contrib/download_prerequisites;环境探测:./configure --enable-checking=release --enable-languages=c,c++ --disable-multilib;编译:make -j$(nproc);安装:make install;验证:gcc -v(应输出 gcc version 5.1.0)。

练习 3:情景设计 进阶

你的服务器是 CentOS 7(自带 gcc 4.8.5),要编译一个要求 C++14 的 POCO 库。写出完整的行动方案:从下载到验证,并说明如何避免影响系统原有的 gcc。

提示

把 3.4~3.7 串起来;"不影响系统 gcc"的关键是 --prefix 和 PATH。

参考答案

wget https://ftp.gnu.org/gnu/gcc/gcc-5.1.0/gcc-5.1.0.tar.bz2 && tar xjfcd gcc-5.1.0;② ./contrib/download_prerequisites 准备 GMP/MPFR/MPC;③ ./configure --prefix=/opt/gcc-5.1.0 --enable-languages=c,c++ --enable-checking=release --disable-multilib;④ make -j$(nproc) && sudo make install;⑤ 验证 /opt/gcc-5.1.0/bin/gcc -v;⑥ 编译 POCO 时把 /opt/gcc-5.1.0/bin 放 PATH 最前面(临时 export 或写 ~/.bashrc)。因为装到了 /opt 独立目录,系统自带的 /usr/bin/gcc 完全不受影响,随时可以切换。

练习 4:实战排障 挑战

实操环境(或虚拟机)里完成:源码安装 GCC 5.1.0 到 /opt/gcc-5.1.0,编译一个 C++14 程序并运行。然后故意制造并排查两个故障:① 程序运行时报 libstdc++.so.6: version 'GLIBCXX_3.4.21' not found;② gcc --version 显示的还是系统老版本。分别写出排查命令与解决步骤。

提示

故障①用 ldd 看库路径、用 LD_LIBRARY_PATH 或复制库解决;故障②用 which gcchash -r 排查 PATH 与命令缓存。

参考答案

① 先 ldd ./app | grep stdc++ 确认链接到 /usr/lib64 的旧库,然后 cp -vf /usr/local/lib64/libstdc++.* /usr/lib64/(root),或 export LD_LIBRARY_PATH=/usr/local/lib64:$LD_LIBRARY_PATH;② which gcc 若输出 /usr/bin/gcc,说明 PATH 里新目录没生效——执行 export PATH=/opt/gcc-5.1.0/bin:$PATH(并写入 ~/.bashrc),再 hash -r 清除缓存后重试 gcc --version。记下每一步的报错原文和解决命令,这就是你的排障笔记。