☰
Ubuntu 18.04 GCC安装与多版本管理全攻略
2026/10/8 20:09:39 网站建设 项目流程

简介:这份资源面向需要在 Ubuntu 18.04 环境下离线部署 GCC 编译工具链的开发者和运维人员,尤其适合内网服务器、无外网条件的实验环境或批量装机场景。压缩包共 25 个文件,以 24 个 deb 安装包和 1 个 sh 脚本为主,整体约 20.05MB,涵盖 gcc-7、cpp-7、binutils 系列以及 libasan4、libgomp1、libquadmath0 等运行库与开发依赖,基本覆盖 GCC 7.3 编译环境所需的组件。资源已获得 3205 人学习下载,说明其在离线安装场景中具有较高的参考价值。借助包内脚本,读者可快速完成依赖顺序安装与配置,避免逐一下载依赖的繁琐过程,同时也能借此理解 GCC 工具链各组件之间的依赖关系,为后续排查编译环境问题提供思路。整体目录结构清晰,适合需要快速搭建本地编译环境或研究 deb 包依赖关系的读者使用。

1. 从 ubuntu18.04gcc.zip 说起:一个压缩包背后到底藏着什么

如果你在搜索引擎里敲下ubuntu18.04gcc.zip,大概率不是想研究压缩算法,而是遇到了一个很具体的场景:手上有一台 Ubuntu 18.04 的机器,或者一个基于它的开发环境,需要把 GCC 编译器装好、配好、跑通。这个标题看起来像个文件名,实际上它指向的是一整套「在 Ubuntu 18.04 上部署 GCC 工具链」的落地需求。Ubuntu 18.04 是个长期支持版本,很多工业控制、嵌入式开发、老项目维护的机器至今还跑着它,而 GCC 作为 Linux 下最核心的编译器,装不上或者装不对,后面的代码编译、交叉编译、驱动构建全都无从谈起。

这个方向适合三类人:一是刚接触 Linux 开发、需要在 Ubuntu 18.04 上把编译环境搭起来的新手;二是维护老项目、发现系统自带的 GCC 版本不够用或者被误删的工程师;三是做嵌入式开发、需要特定版本 GCC 来编译固件或内核模块的从业者。核心要解决的问题就三个:怎么装、装哪个版本、装完怎么验证和切换。别小看这三件事,ubuntu安装gcc失败是个高频搜索词,说明翻车的人不在少数。接下来我会按「先搞清楚系统里有什么、再决定怎么装、最后处理版本冲突」的顺序,把这条路径拆开讲透。

2. Ubuntu 18.04 上的 GCC 安装路径:从 apt 到源码编译

2.1 先摸清系统自带的 GCC 状态

在动手装任何东西之前,先看系统里现在是什么情况。Ubuntu 18.04 默认的软件源里带的是 GCC 7.5.0,这个版本对大多数常规开发够用,但如果你要编译较新的内核或者某些依赖 C++17 以上特性的项目,就可能不够。打开终端,依次执行下面几条命令,把现状摸清楚。

# 查看当前 gcc 版本 gcc --version # 查看 gcc 实际指向哪个可执行文件 which gcc # 列出系统里已经安装的所有 gcc 相关包 dpkg -l | grep gcc # 查看当前系统架构,确认是 amd64 还是 arm64 uname -m

这几条命令的输出信息很关键。gcc --version告诉你当前默认编译器版本;which gcc让你知道它到底指向/usr/bin/gcc还是某个手动装的路径;dpkg -l | grep gcc能看出系统里是不是已经装了多个版本的 GCC,比如gcc-7、gcc-8同时存在;uname -m则决定了你后面下载的包或者源码编译时的目标架构。很多人ubuntu安装gcc失败,第一步就错在没确认系统里已经有什么,直接上手装,结果版本冲突或者依赖断裂。

如果gcc --version提示 command not found,说明系统里根本没装 GCC,或者环境变量 PATH 被改坏了。这时候先别急着重装系统,用apt补装就行。如果输出的是 GCC 7.5.0,那说明默认版本还在,你可以选择升级或者额外装一个新版本共存。

2.2 用 apt 安装指定版本的 GCC

Ubuntu 18.04 的官方源里能直接拿到的 GCC 版本包括 7 和 8,再高的版本比如 GCC 9、10、11 就需要加 PPA 或者手动编译。对于大多数场景,我建议先用 apt 装一个稳定的版本,别一上来就源码编译,那是最后的手段。

# 更新软件包列表,确保源信息是最新的 sudo apt update # 安装 gcc-8 和 g++-8,同时装上对应的基础依赖 sudo apt install -y gcc-8 g++-8 # 如果需要 GCC 7 的完整工具链,也可以显式安装 sudo apt install -y gcc-7 g++-7 # 安装 make、binutils 等编译辅助工具 sudo apt install -y make binutils build-essential

这里有几个参数和选择需要说明。gcc-8和g++-8是分开的包,只装gcc-8不会有 C++ 编译器,如果你的项目里有.cpp文件,必须把g++-8一起装上。build-essential是个元包,它会自动拉取gcc、g++、make、libc6-dev等一整套基础编译环境,适合全新系统一次性配好。-y参数是自动确认,避免安装过程中卡在交互提示上。

装完之后,系统里会同时存在多个 GCC 版本,但默认的gcc命令仍然指向原来的版本。你需要用update-alternatives来管理默认指向,这是 Ubuntu 下切换多版本工具的标准做法。

# 把 gcc-8 注册到 alternatives 系统里,优先级设为 80 sudo update-alternatives --install /usr/bin/gcc gcc /usr/bin/gcc-8 80 # 把 gcc-7 也注册进去,优先级设为 70 sudo update-alternatives --install /usr/bin/gcc gcc /usr/bin/gcc-7 70 # 交互式选择默认的 gcc 版本 sudo update-alternatives --config gcc

--install后面的四个参数分别是:链接组的目标路径、组名、实际可执行文件路径、优先级。优先级数字越大,自动模式下的默认选择就越靠前。--config会弹出一个列表让你手动选,选完之后/usr/bin/gcc这个软链接就会指向你选的版本。同样的操作也要对g++做一遍,否则会出现 C 编译器版本和 C++ 编译器版本不一致的玄学问题。

注意:update-alternatives只影响通过它注册过的命令。如果你之前手动改过/usr/bin/gcc的软链接,或者把某个路径硬编码进了环境变量,alternatives 可能不生效。这时候用ls -l /usr/bin/gcc看一下软链接到底指向哪里。

2.3 源码编译安装更高版本的 GCC

当 apt 源里找不到你需要的版本时,比如项目要求 GCC 9 以上,就只能源码编译。这条路耗时较长,但可控性最强。以下载 GCC 9.5.0 为例,整个流程包括下载源码、安装依赖、配置、编译、安装五步。

# 安装源码编译所需的依赖库 sudo apt install -y libgmp-dev libmpfr-dev libmpc-dev libisl-dev # 下载 GCC 9.5.0 源码包 wget https://ftp.gnu.org/gnu/gcc/gcc-9.5.0/gcc-9.5.0.tar.gz # 解压到当前目录 tar -xzf gcc-9.5.0.tar.gz # 进入源码目录 cd gcc-9.5.0 # 下载 GCC 依赖的第三方库(gmp、mpfr、mpc) ./contrib/download_prerequisites

download_prerequisites这个脚本会自动下载并解压 GCC 编译所需的三个数学库,省去手动处理的麻烦。如果网络环境导致下载失败,也可以手动去对应官网下载后放到源码目录里。依赖准备好之后,创建一个独立的构建目录,不要在源码目录里直接 configure,这是避免污染源码树的标准做法。

# 回到上级目录,创建构建目录 cd .. mkdir gcc-9.5.0-build cd gcc-9.5.0-build # 配置编译选项 ../gcc-9.5.0/configure \ --prefix=/usr/local/gcc-9.5.0 \ --enable-languages=c,c++ \ --disable-multilib \ --disable-bootstrap # 启动编译,-j 后面的数字根据 CPU 核心数调整 make -j$(nproc) # 安装到指定前缀目录 sudo make install

--prefix决定了安装路径,我习惯把第三方编译的 GCC 放到/usr/local/下面,和系统自带的/usr/bin/隔离,避免覆盖系统编译器导致系统工具链崩溃。--enable-languages=c,c++表示只编译 C 和 C++ 前端,如果你需要 Fortran 或者 Go 前端,可以加上对应的语言名。--disable-multilib在 64 位系统上只生成 64 位库,减少编译时间和磁盘占用。--disable-bootstrap跳过三阶段自举,能显著缩短编译时间,代价是编译器本身的优化程度略低,但对日常使用影响不大。

make -j$(nproc)里的$(nproc)会自动读取 CPU 核心数,比如 8 核机器就相当于make -j8。编译 GCC 是个重活,8 核机器大概需要 20 到 40 分钟,内存建议不低于 4GB,否则可能在链接阶段被 OOM killer 干掉。编译完成后make install会把可执行文件放到/usr/local/gcc-9.5.0/bin/下面,你还需要把这个路径加到 PATH 里,或者用 alternatives 注册进去。

# 把新编译的 GCC 加入 alternatives 管理 sudo update-alternatives --install /usr/bin/gcc gcc /usr/local/gcc-9.5.0/bin/gcc 90 sudo update-alternatives --install /usr/bin/g++ g++ /usr/local/gcc-9.5.0/bin/g++ 90 # 验证版本切换是否生效 gcc --version

到这里,Ubuntu 18.04 上安装 GCC 的三条主要路径就讲完了:apt 装现成包、alternatives 管多版本、源码编译装新版。选哪条路取决于你的项目对 GCC 版本的要求和你能接受的折腾程度。

3. 装完 GCC 之后:环境变量、多版本共存与交叉编译配置

3.1 环境变量配置的常见翻车点

GCC 装好了,但gcc --version显示的版本不对,或者编译时报找不到头文件,这类问题多半出在环境变量上。ubuntu环境变量配置错误是个高频搜索词,说明很多人在这上面栽过跟头。Linux 下和 GCC 相关的环境变量主要有三个:PATH、LIBRARY_PATH、C_INCLUDE_PATH。

PATH决定 shell 去哪些目录找可执行文件。如果你把新 GCC 的bin目录加到了PATH最前面,那gcc命令就会优先找到新版本。但要注意,PATH的顺序很关键,加在末尾等于没加。检查方法很简单:

# 查看当前 PATH 的完整内容,注意冒号分隔的顺序 echo $PATH # 确认 gcc 实际被解析到哪个路径 type -a gcc

type -a gcc会列出所有能匹配到gcc的路径,按PATH顺序排列,第一个就是实际执行的。如果第一个不是你期望的版本,要么调整PATH顺序,要么用 alternatives 统一管理。

LIBRARY_PATH和LD_LIBRARY_PATH容易混淆。LIBRARY_PATH是编译链接阶段用的,告诉链接器去哪里找.a和.so文件;LD_LIBRARY_PATH是运行阶段用的,告诉动态加载器去哪里找共享库。编译时找不到-lstdc++通常是LIBRARY_PATH的问题,运行时提示error while loading shared libraries则是LD_LIBRARY_PATH的问题。我一般会在~/.bashrc里显式设置这两个变量,但只针对当前用户,不动系统级配置。

# 在 ~/.bashrc 末尾追加以下内容 export PATH=/usr/local/gcc-9.5.0/bin:$PATH export LIBRARY_PATH=/usr/local/gcc-9.5.0/lib64:/usr/local/gcc-9.5.0/lib:$LIBRARY_PATH export LD_LIBRARY_PATH=/usr/local/gcc-9.5.0/lib64:/usr/local/gcc-9.5.0/lib:$LD_LIBRARY_PATH

改完~/.bashrc后记得source ~/.bashrc让它生效。这里有个血泪经验:不要把新路径直接覆盖掉原来的PATH,一定要用$PATH把旧值拼在后面,否则系统命令可能全部失效,连ls都跑不了。

3.2 多版本 GCC 共存的目录规划

一台机器上同时存在 GCC 7、8、9 甚至更高版本是常态,关键是怎么让它们互不干扰。我的做法是按版本号分目录存放,每个版本有独立的bin、lib、include,然后通过 alternatives 或者环境变量来切换。

版本安装路径管理方式适用场景
GCC 7.5.0/usr/bin/gcc-7apt + alternatives系统默认,基础编译
GCC 8.4.0/usr/bin/gcc-8apt + alternatives较新 C++ 特性
GCC 9.5.0/usr/local/gcc-9.5.0源码编译 + PATH新标准项目
GCC 11.2.0/usr/local/gcc-11.2.0源码编译 + PATH内核/驱动编译

这张表是我在一台开发机上实际维护的版本布局。系统自带的 GCC 7 不动它,因为很多系统工具依赖它;GCC 8 用 apt 装,方便快速切换;GCC 9 和 11 用源码编译,放在/usr/local/下,需要时通过PATH或者 alternatives 切过去。这样做的代价是磁盘占用多一些,但换来的是版本隔离,不会出现「升级 GCC 后系统命令全挂」的惨剧。

切换版本时,除了gcc和g++,别忘了cc、c++、cpp这些命令也可能需要同步。cc通常是gcc的软链接,c++是g++的软链接,但有些构建脚本会直接调用cc,如果它指向旧版本,编译结果可能不符合预期。用ls -l /usr/bin/cc确认一下指向,必要时也用 alternatives 注册。

3.3 交叉编译场景下的 GCC 配置

嵌入式开发里经常需要在 Ubuntu 18.04 上编译目标平台是 ARM 或 RISC-V 的代码,这时候用的不是本机 GCC,而是交叉编译工具链。ch32v在gcc编译器下定义中断函数这个搜索词就反映了 RISC-V 或 ARM 平台下用 GCC 的典型场景。交叉编译工具链通常以arm-linux-gnueabihf-gcc或riscv64-unknown-elf-gcc这样的名字出现,安装方式有两种:apt 装现成的,或者从芯片厂商官网下载。

# 安装 ARM 交叉编译工具链 sudo apt install -y gcc-arm-linux-gnueabihf g++-arm-linux-gnueabihf # 安装 RISC-V 交叉编译工具链(如果源里有的话) sudo apt install -y gcc-riscv64-unknown-elf # 验证交叉编译器是否可用 arm-linux-gnueabihf-gcc --version

交叉编译时,--sysroot参数指定目标平台的根文件系统路径,-march和-mabi指定目标架构和 ABI。比如编译 RISC-V 代码时:

# 编译一个简单的 RISC-V 程序 riscv64-unknown-elf-gcc -march=rv32imac -mabi=ilp32 -o test.elf test.c

-march=rv32imac表示目标架构是 32 位 RISC-V,支持整数、乘除、原子和压缩指令集;-mabi=ilp32表示 ABI 是 32 位整数、长整型和指针。这两个参数必须和目标硬件匹配,写错了编译能过但运行会出问题。中断函数的定义在 RISC-V GCC 下通常用__attribute__((interrupt))来标记,具体写法取决于芯片厂商的头文件封装,但底层机制是 GCC 的属性扩展。

提示:交叉编译工具链的版本要和目标平台的内核版本、C 库版本匹配。用高版本 GCC 编译的二进制放到低版本 C 库的系统上跑,可能出现GLIBC_2.xx not found的错误。遇到这种情况,要么降低编译时的 C 库依赖,要么在目标平台上更新 C 库。

4. GCC 安装与使用的避坑清单:从依赖断裂到版本回退

4.1 坑一:apt 安装时报依赖错误

现象:执行sudo apt install gcc-8时提示The following packages have unmet dependencies,或者卡在Unable to correct problems, you have held broken packages。

原因:Ubuntu 18.04 的软件源可能被改过,或者之前装过第三方 PPA 导致依赖关系混乱。常见的情况是libc6-dev版本和gcc-8要求的版本不匹配,或者binutils被手动升级过。

解决:先用sudo apt --fix-broken install尝试自动修复,然后sudo apt update刷新源。如果还不行,用apt-cache policy gcc-8查看候选版本和依赖要求,手动把冲突的包降级或升级到匹配版本。实在搞不定就sudo apt install -f强制修复,但要注意这可能会卸载一些包,操作前先看清楚提示。

4.2 坑二:源码编译 GCC 时内存不足被 kill

现象:make -j8跑到一半突然报gcc: internal compiler error: Killed (program cc1plus),或者直接提示virtual memory exhausted。

原因:GCC 编译过程中cc1plus这个进程非常吃内存,尤其是编译 C++ 前端时,单个进程可能占用 1GB 以上。如果-j的并行数太高,多个cc1plus同时跑,物理内存加交换分区都不够用,就会被系统的 OOM killer 干掉。

解决:降低并行数,比如从-j8改成-j2或-j1,牺牲时间换稳定。同时检查交换分区大小,free -h看一下 swap 是不是太小,必要时临时增加 swap 文件。另外,--disable-bootstrap也能减少编译过程中的内存峰值。

4.3 坑三:升级 GCC 后系统命令异常

现象:把/usr/bin/gcc的软链接直接指向新版本后,apt、dpkg甚至ls开始报错,提示找不到某些共享库。

原因:Ubuntu 系统里很多工具是用系统自带的 GCC 编译的,依赖特定版本的libstdc++。如果你把默认gcc换成了高版本,但libstdc++没有同步更新,或者新版本的库路径没有加到LD_LIBRARY_PATH,就会导致动态链接失败。

解决:永远不要直接覆盖/usr/bin/gcc的软链接。用update-alternatives管理,或者把新 GCC 放到/usr/local/下通过PATH切换。如果已经搞坏了,用sudo update-alternatives --config gcc切回旧版本,或者手动把软链接恢复成/usr/bin/gcc-7。

4.4 坑四:gcc 升级后版本号没变

现象:明明装好了 GCC 9,gcc --version还是显示 7.5.0,或者which gcc指向的路径不对。

原因:PATH里旧版本的路径排在前面,或者 shell 缓存了旧的命令位置。gcc升级后为啥还是旧版本这个搜索词说的就是这种情况。

解决:先hash -r清除 shell 的命令哈希缓存,然后type -a gcc看所有匹配路径。如果新版本路径在PATH里但排在后面,调整~/.bashrc里的顺序,把新路径放到$PATH前面。如果是 alternatives 管理的,用sudo update-alternatives --config gcc确认选中的是哪个版本。

4.5 坑五:编译时找不到头文件或库文件

现象:编译时报fatal error: stdio.h: No such file or directory,或者链接时提示cannot find -lstdc++。

原因:新装的 GCC 没有正确配置头文件搜索路径,或者LIBRARY_PATH没有包含新版本的库目录。源码编译 GCC 时如果--prefix指定的路径和实际安装路径不一致,也会导致这个问题。

解决:用gcc -v -E -x c /dev/null查看 GCC 实际搜索的头文件路径,确认/usr/local/gcc-9.5.0/include在列表里。如果不在,检查--prefix是否正确,或者手动设置C_INCLUDE_PATH和LIBRARY_PATH。对于-lstdc++找不到的情况,确认g++是否和gcc版本一致,以及libstdc++.so是否在库搜索路径下。

5. 验证 GCC 安装是否真正可用:编译测试与版本回退技巧

装完 GCC 只是第一步,真正要确认的是它能不能正常工作。我习惯用三个层次的测试来验证:最小编译测试、多版本切换测试、回退测试。这三个测试跑完,基本能覆盖 90% 的安装问题。

最小编译测试用一个包含 C 和 C++ 的混合项目,确认gcc和g++都能正常调用,头文件和库文件都能找到。

# 创建一个测试目录 mkdir -p ~/gcc-test && cd ~/gcc-test # 写一个简单的 C 程序 cat > test.c << 'EOF' #include <stdio.h> int main() { printf("C compile OK, GCC version: %d.%d.%d\n", __GNUC__, __GNUC_MINOR__, __GNUC_PATCHLEVEL__); return 0; } EOF # 写一个简单的 C++ 程序,用到 C++17 特性 cat > test.cpp << 'EOF' #include <iostream> #include <optional> int main() { std::optional<int> val = 42; std::cout << "C++ compile OK, value: " << *val << std::endl; return 0; } EOF # 编译 C 程序 gcc -o test_c test.c && ./test_c # 编译 C++ 程序,指定 C++17 标准 g++ -std=c++17 -o test_cpp test.cpp && ./test_cpp

__GNUC__、__GNUC_MINOR__、__GNUC_PATCHLEVEL__是 GCC 预定义宏,分别对应主版本号、次版本号和补丁号。运行test_c会打印出当前编译器的实际版本,这比gcc --version更可靠,因为它反映的是编译时真正生效的版本。C++ 测试里用了std::optional,这是 C++17 的特性,如果编译器版本不够或者标准没指定对,编译会直接报错,能快速暴露问题。

多版本切换测试的目的是确认 alternatives 或者 PATH 切换是否生效。写一个脚本,依次切换版本并记录gcc --version的输出。

# 记录当前版本 echo "=== 当前默认版本 ===" gcc --version | head -1 # 切换到 GCC 8 sudo update-alternatives --set gcc /usr/bin/gcc-8 echo "=== 切换到 GCC 8 ===" gcc --version | head -1 # 切换到源码编译的 GCC 9 sudo update-alternatives --set gcc /usr/local/gcc-9.5.0/bin/gcc echo "=== 切换到 GCC 9 ===" gcc --version | head -1 # 切回默认版本 sudo update-alternatives --auto gcc echo "=== 恢复自动模式 ===" gcc --version | head -1

--set是强制指定某个版本,--auto是恢复自动选择模式,按优先级决定默认版本。这个脚本跑一遍,如果每个版本的输出都符合预期,说明 alternatives 配置正确。如果某个版本切换后gcc --version没变,检查该版本是否已经注册到 alternatives 里,用update-alternatives --list gcc查看已注册的版本列表。

回退测试是最容易被忽略但最关键的一步。很多人在升级 GCC 之后发现项目编译不过,想切回旧版本,结果发现旧版本的软链接已经被覆盖了。所以我在每次升级之前,都会先记录当前默认版本的路径,并确认旧版本的可执行文件还在。

# 升级前记录当前 gcc 路径 readlink -f $(which gcc) > ~/gcc-backup.txt cat ~/gcc-backup.txt # 如果升级后需要回退,直接用记录的路径恢复 # 假设备份文件里是 /usr/bin/gcc-7 sudo update-alternatives --set gcc /usr/bin/gcc-7 sudo update-alternatives --set g++ /usr/bin/g++-7

readlink -f会解析软链接的最终目标路径,把它存到文件里,相当于给自己留了一颗后悔药。回退时用--set切回去就行,不需要重新安装。如果连 alternatives 都乱了,还可以直接用绝对路径调用旧版本编译器,比如/usr/bin/gcc-7 -o test test.c,临时绕过默认版本的问题。

最后一个技巧是关于vscode gcc一键编译运行的配置。如果你在 Ubuntu 18.04 上用 VS Code 写 C/C++,tasks.json里的command字段默认是gcc,它走的是系统默认版本。如果你想固定用某个版本,把command改成绝对路径,比如/usr/local/gcc-9.5.0/bin/gcc,这样无论系统默认版本怎么切,VS Code 里编译用的始终是你指定的那个。c_cpp_properties.json里的compilerPath也要同步改,否则 IntelliSense 的提示和实际编译行为可能不一致。

这套验证流程我用了好几年,从 Ubuntu 16.04 到 18.04 再到 20.04,基本没翻过车。核心习惯就一条:每次动编译器之前先备份当前路径,装完先跑最小编译测试,确认没问题再切默认版本。GCC 这东西不像应用软件,它和系统底层绑得太深,一旦搞坏修复成本很高。希望帮到你。

本文还有配套的精品资源,点击获取

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询