
简介在 Ubuntu 20.04 离线环境中搭建 GCC 编译环境常因依赖缺失而卡壳这款资源将 gcc-9、binutils、libc6-dev、libasan5 等 30 个 .deb 依赖包与一键安装脚本 do.sh 整合为一个整体专门解决离线安装时依赖关系复杂、逐一手动配置易出错的问题。GCC 作为开源编译器套件支持 C、C、Fortran 等语言是源码编译与软件部署的基础工具资源打包时已考虑 amd64 架构适配标准 Ubuntu 20.04 x86_64 系统。压缩包仅 29.83MB共 31 个文件覆盖 C/C 编译所需的完整运行库同时附带的 do.sh 脚本自动处理 dpkg 安装顺序与 PATH 配置免去手动逐条敲命令的麻烦。整个离线包可放入 U 盘或公司内部镜像仓库批量部署时只需重复执行脚本即可大幅减少排错时间。资源已获得 8674 人学习下载特别适合没有外网连接、资源有限或网络受限的现场环境如内网服务器、开发测试机、安全隔离区等场景为开发者提供了一条稳定、省时的工具链准备路径。1. ubuntu20.04离线安装gcc.zip解的是内网编译的燃眉之急一台内网 Ubuntu 20.04没有外网apt update 卡在 connection timeout然后终端里弹出gcc: command not found。研发网、学校机房、工控现场这样的场景太常见了。网上 ubuntu20.04 安装教程很多但真正讲离线装编译器的却没几个说全。所谓 ubuntu20.04 离线安装 gcc.zip核心思路是拿一台能联网的 Ubuntu 20.04 当“提货机”用 apt 把 gcc 和它背后整棵依赖树的 deb 包全部拉下来zip 打包后拷贝进内网再用 dpkg 离线装上。整个过程不用编译源码、不用配本地镜像源十几分钟就能把 gcc、g、make 和基础头文件补全。这篇笔记写给三类人守在内网开发机前却装不了编译器的开发者、要给十几台机器批量装同版本编译环境的人以及刚装好 Ubuntu 20.04 却发现 apt 全部超时的新手。2. 先理解离线安装的本质gcc 不是单个 deb是一整棵依赖树2.1 为什么只下载一个 gcc.deb 救不了你很多人的第一反应是去 packages.ubuntu.com 下载一个gcc_*.deb然后 U 盘拷贝进内网dpkg -i直接装。结果终端一执行报错满天飞。dpkg: dependency problems prevent configuration of gcc: gcc depends on gcc-9 ( 9.3.0); however: Package gcc-9 is not installed.原因在于 Ubuntu 的 gcc 是一个元包meta package它本身只有几十 KB真正干活的是 gcc-9、cpp-9、binutils 这一串程序。apt 在联网时自动帮你算好依赖离线时你只能自己把这整条链条背上。这就是“ubuntu 安装 gcc 失败”最常见的原因不是权限不是源坏了是依赖没带齐。gcc 在 Ubuntu 20.04 上至少涉及下面这层包名在链条里的角色gcc元包负责生成 /usr/bin/gcc 链接gcc-9GCC 9 编译器本体实际调用 cc1 的入口cpp / cpp-9C 预处理器binutilsas 汇编器、ld 链接器编译链接阶段必需libgcc-9-devGCC 运行时库和头文件libc6-devglibc 的开发头文件和静态库linux-libc-dev内核 UAPI 头文件编译部分系统调用相关代码时会用到这里还没算上中转依赖比如 binutils 自身依赖的libbinutils、binutils-common以及 gcc-9 依赖的libisl22、libmpc3、libmpfr6这些数学库包。所以说离线安装 gcc 的第一步不是找安装包而是先摸清依赖树有多大。2.2 用 apt-cache depends 把整棵依赖树挖出来在联网机器上apt 自带一个递归查询依赖的命令比手动一层层翻 packages.ubuntu.com 快得多。我一般会配合LANGC使用避免中文系统把Depends翻译成“依赖:”导致脚本解析出错。cd ~ # 递归列出 gcc 的完整依赖包名排除推荐和建议排除冲突/替代/提供关系 LANGC apt-cache depends --recurse -i --no-recommends --no-suggests \ --no-conflicts --no-breaks --no-replaces --no-provides gcc \ | grep ^[^ ] | tr -d : | sort -u package_list.txt # 看一眼总共多少个包 wc -l package_list.txt这段命令里最值得解释的是后半段过滤。apt-cache depends原始输出里根包名顶格写依赖项前面有缩进例如gcc 依赖: gcc-9 gcc-9 依赖: binutilsgrep ^[^ ]就是只保留顶格行把缩进的描述行全部丢掉留下的就是 gcc、gcc-9、binutils 这些真正的包名。tr -d :去掉个别包名后面的冒号sort -u去重。最终 package_list.txt 里就是一条干净的包名清单之后不管是 apt-get download 还是人工核对都以这份清单为准。注意-i --no-recommends --no-suggests这三个参数是避免把 Recommends 和 Suggests 里的包卷进来。比如 gcc 的推荐包里可能有 gcc-multilib那是交叉编译多库用的内网装 C 编译器用不上。参数加得越严zip 包越小后面 dpkg 装的时候越不容易碰出版本冲突。2.3 动手前先做版本匹配对齐两台机器的 20.04 小版本依赖树摸清了还有一个比依赖更优先的问题版本对齐。Ubuntu 20.04 本身还有小版本差异比如 20.04.1 和 20.04.6前者可能自带 libc6 2.31-0ubuntu9.1后者已经滚到 9.7。如果把联网机器源里的 libc6 下载下来塞给老版本机器dpkg 会直接拒绝因为 libc6 是系统最底层的库涉及所有二进制运行不允许随便降级或跳级。所以打包之前先在目标内网机器上执行dpkg -l libc6 binutils | tee libc_versions.txt如果目标机器上压根没装过 gcc就重点看 libc6 的版本号。然后在联网机器上再跑一次同样的命令确认两个版本能对得上apt-cache policy libc6 binutils比对原则很简单联网机器下载的 deb 包版本不能高于目标机器已安装的版本否则 dpkg 会因为“已安装的版本太旧”或“目标版本比已安装版本旧”卡住。保守做法是让联网机器也把 apt 源固定到 focal、focal-updates 里和目标机器一致的仓库地址别在打包前几天手贱更新过系统。3. 拉取 deb 包并打包 zip把依赖清单变成可搬运的文件3.1 在联网机器上把全部依赖逐个下载到同一目录拿到 package_list.txt 之后就是批量下载环节。这里我推荐用apt-get download而不是apt-get install --download-only因为后者会把 deb 放到/var/cache/apt/archives机器里以前装过的包残余也会混在同一个目录里不好区分哪些是本次拉取的。mkdir -p ~/gcc-offline cd ~/gcc-offline # 按清单逐个下载失败时单独记录 while read pkg; do apt-get download $pkg 2/dev/null || echo $pkg 下载失败 missing.txt done ../package_list.txt # 检查有没有遗漏 cat missing.txt 2/dev/null || echo 无缺失包 ls *.deb | wc -l这段逻辑不复杂但有一个细节要说明apt-get download只下载指定包不会自动处理依赖。因为我们前面已经用apt-cache depends算好了完整清单所以这里不需要再做任何二次解析。|| echo的作用是把下载失败的包名记到 missing.txt多半是因为源里没有对应版本这时候要做的是先sudo apt-get update再重跑一遍循环。如果清单不太长也可以偷懒用一条命令apt-get download $(cat ../package_list.txt)但这种方式一旦某个包下载失败整条命令中断后面的包全不下载了。所以我宁可用 while 循环慢几秒钟但每个包独立执行失败了还能继续。内网环境本来就折腾不起少一次往返就多一分效率。3.2 用 zip 打包 deb 并留下校验值deb 文件全部下载到位后直接在当前目录压缩成 zip。这步没有技术难度但有一点容易翻车别在压缩时带上一层层目录结构比如zip -r gcc_offline.zip ~/gcc-offline/*.deb这样解压出来会有多层父目录后面dpkg -i *.deb在子目录里执行时路径稍微一错就找不到包。cd ~/gcc-offline # 把当前目录下的所有 deb 和包清单一起打进 zip zip -r gcc_offline.zip *.deb package_list.txt # 列出压缩包内容确认结构是扁平的 unzip -l gcc_offline.zip | head -20 # 生成校验值拷贝完比对用 sha256sum gcc_offline.zip gcc_offline.zip.sha256这里附一句unzip -l的输出都是deb 包名这种扁平结构没有home/ubuntu/...前缀说明压缩路径对了。sha256sum 文件是给 U 盘拷贝或内网 FTP 传输时校验完整性的虽然 deb 包一般不会损坏但加了这层核对到了内网发现安装报错时能快速排除“包在传输途中坏了”这个嫌疑人。3.3 跨机器搬运的三条实操建议第一传输介质建议直接用 U 盘格式化成 exFAT 或 NTFS 都行zip 包里已经是压缩态二进制文件系统差异影响不大。第二确认两台机器架构一致在线机器是 amd64目标机器也是 amd64下载的 deb 才能用。第三到了内网先不要急着解压先看 zip 大小和 deb 数量跟打包时有个心理预期再开始安装。这套“依赖清单 批量下载 zip 打包”的流程本质上和 linux 离线安装 node、离线装 python 依赖是同一套思路只是不同语言生态用的包管理工具不一样。gcc 这里用的是 deb 包闭包理解了闭包概念后续遇到内网装其他软件都能套用。4. 在离线机器上安装解压后按 dpkg 规则批量装再验证4.1 解压后先核对包清单再确认目标机器状态把 zip 传到内网机器后接下来的操作全部在这台断网机器上执行。mkdir -p ~/gcc-offline cd ~/gcc-offline # 解压保持扁平结构 unzip gcc_offline.zip # 核对包数量和解压结果 ls *.deb | wc -l # 看目标机器上是否已有旧版本库 dpkg -l | grep -E libc6|gcc|binutils | head -20解压这一步不复杂但不要跳过dpkg -l的检查。如果目标机器装过老版本 gcc后面安装时就会出现“版本冲突”或“alternatives 没切换”两个分支问题。提前看到旧版本存在后面遇到类似报错心里就有底了。4.2 一条 dpkg -i *.deb 批量安装失败就再跑一次安装动作本质上就是一条命令sudo dpkg -i *.deb很多人看到这条命令会担心依赖顺序问题binutils 还没装上gcc-9 就开始配置了怎么办实际上 dpkg 在处理一批 deb 时内部会先做一轮拓扑排序把依赖关系理清后再逐个解包和配置。所以同一批 deb 一次性喂给 dpkg成功率远比一条条dpkg -i高。真正会遇到的情况是解包全部成功但配置阶段有几个包因为依赖链没闭合而中止。这时候不用急着加参数直接再跑一次sudo dpkg -i *.deb第二次 dpkg 会把第一次已经解包但未配置的包继续配置完。如果第二次还有报错就执行sudo dpkg --configure -a这个命令是 dpkg 的兜底逻辑把所有处于“已解包待配置”状态的包收尾。注意如果报错信息里出现“尚未安装”的字样说明依赖列表确实漏了包这在离线环境里无法用apt-get install -f修复唯一解法是回联网机器按第 2 章的递归清单补下载重新打包带进来。4.3 安装完成后用三条命令验证编译链路安装完不等于能用内网最怕的就是装完了发现链接器缺失或者头文件路径不对。我的验证习惯是三步走# 第一层版本命令 gcc --version | grep gcc g --version | grep g make --version | grep GNU Make # 第二层真实编译一个最小 C 程序 echo #include stdio.h int main() { printf(offline gcc ok\n); return 0; } /tmp/t.c gcc /tmp/t.c -o /tmp/t /tmp/t版本命令只能证明二进制存在真正证明编译器可用的是最后一步写一个最小 C 文件走完预处理、编译、汇编、链接全流程然后执行产物。如果这一步能输出offline gcc ok说明 gcc、binutils、libc6-dev、头文件这四层全部正常。我见过不少“版本号能弹出来但一编译就报找不到 stdio.h”的内网机器多半是 libc6-dev 没装或者 linux-libc-dev 版本不匹配所以第三步才是重点。5. 离线安装 gcc 的 5 个常见问题排查现象、原因、解法5.1 报“依赖问题但尚未安装”依赖列表不完整现象sudo dpkg -i *.deb时大量出现gcc depends on gcc-9 ( 9.3.0); however: Package gcc-9 is not installed。原因打包时只执行了apt-get download gcc没有递归分析 gcc-9、binutils 那一层的二次依赖或者递归时用了--no-recommends但没排除掉Suggested包。解法回到联网机器按第 2.2 节的完整递归命令重新生成 package_list.txt确认wc -l有几十行而不是一行然后重跑下载循环和打包。5.2 gcc 能编译 C但 g 和 make 还是 command not found现象gcc --version正常编译 C 文件通过但执行g提示未找到命令make也一样。原因gcc 元包只管 C 编译器g 由 g/g-9 提供make 是完全独立的包它们都不在 gcc 的依赖链里。解法打包起点改成build-essential它会拉起 gcc、g、make、dpkg-dev 等一整套构建工具。修改 2.2 节命令最后的gcc参数为build-essential即可复用同一套流程。如果你的内网机器只跑 C 代码这一步可以跳过但大多数场景迟早要碰 C。5.3 升级后 gcc --version 还是旧版本alternatives 没切换现象机器原本有 gcc-7离线装完 gcc-9 后gcc --version依然显示 7.5.0。原因/usr/bin/gcc 这个路径是由 update-alternatives 管理的符号链接新包安装不会自动把链接切到 gcc-9。解法sudo update-alternatives --install /usr/bin/gcc gcc /usr/bin/gcc-9 100 sudo update-alternatives --config gcc执行 config 后会列出所有候选项输入对应数字把 gcc-9 设为当前版本。这就是很多人搜“gcc 升级后为啥还是旧版本”时真正需要的答案不是装失败了是切换没做。5.4 从 Windows 中转后再解压权限位全丢了现象zip 包从 Windows 机器通过微信或 U 盘拷贝进内网 Linux解压后 deb 文件都在但sudo dpkg -i *.deb报权限错误或者 postinst 脚本执行失败。原因Windows 上的 WinRAR、7-Zip 解压时不会保留 Unix 权限位deb 包内控制脚本可能失去执行权限。解法内网 Linux 机器上直接用unzip解压不要在 Windows 侧先解压再拷贝。如果已经在 Windows 解压过了进入目录后执行sudo chmod -R 755 .先兜底恢复一批权限再跑 dpkg。5.5 下载的 libc6 比目标机器新dpkg 拒绝安装现象安装过程中报libc6: 版本 (2.31-0ubuntu9.7) 已存在或未满足的依赖 libc6-dev ( 2.31)再往下走报错越来越多。原因联网机器的 apt 源已经滚到了 20.04 后期补丁版本目标机器是早期 20.04libc6 版本低于下载包。解法打包前严格比对两台机器的 libc6 版本。最稳妥的办法是把联网机器的 sources.list 换成与目标机器一致的镜像源并且不启用比目标机器更新的 updates 或 security 仓库。宁可下载略旧一两个小版本的包也不能带一个目标机器装不上的高版本进去。6. 装完整条工具链后把 gcc-9 设为默认并留一个离线副本安装验证通过后还有两件顺手的事值得做。第一件是确认 gcc 和 g 的默认版本。Ubuntu 20.04 的 gcc 链接由 update-alternatives 管理如果你机器上以前有过老版本或者打包时不小心把多个 gcc 版本都拉进来了就需要手动指定默认项sudo update-alternatives --install /usr/bin/gcc gcc /usr/bin/gcc-9 100 sudo update-alternatives --install /usr/bin/g g /usr/bin/g-9 100 sudo update-alternatives --config gcc sudo update-alternatives --config g第一行的 100 是优先级数值越大越优先。手动 config 时直接选 gcc-9 对应的序号即可。这一步做完再用gcc --version确认已经是 9.x整个离线编译器环境就算真正稳定了。第二件是给这个 zip 包留下归档习惯。我一般会把文件名改成带版本和架构的格式比如gcc-9.4.0-focal-amd64-offline.zip散落在跳板机固定目录里。这么做的好处是下次任何一台内网机器要装编译器直接拷走这个包不用再找联网机器重新拉依赖。版本号写进文件名也避免两台机器装出不同编译器版本导致编译产物不兼容。这套离线闭包方案不只对 gcc 有效。以后内网要装 node、要补 python 依赖甚至要给特定项目装老版本工具链都是同样流程在线机器算出依赖闭环离线机器解压安装。区别只是包管理器和依赖树大小。我后来养成的习惯是把这份 package_list.txt 也留在 zip 里哪怕过半年忘了当时装过什么解压出来看一眼清单就全想起来了。希望帮到你。本文还有配套的精品资源点击获取