Ubuntu 18.04离线安装GCC7:dpkg依赖与版本切换实战

发布时间:2026/10/29 2:35:18
Ubuntu 18.04离线安装GCC7:dpkg依赖与版本切换实战

简介:面向 Ubuntu 18.04 环境下无法联网、需要在内网或离线机器上搭建 C/C++ 编译环境的开发者与运维人员,这份压缩包提供了一套可直接用 dpkg 安装的 GCC 7 依赖集合,用于解决缺少编译工具链、apt 源不可达以及依赖版本不匹配等常见问题。包内共 25 个文件,以 24 个 deb 安装包和 1 个 sh 脚本为主:deb 部分覆盖 gcc-7 及 g++ 相关组件、cpp 预处理器、binutils 二进制工具,以及 libasan、libtsan、libgomp 等运行时与优化支持库;脚本则用于批量安装并处理安装顺序,压缩包整体约 20.05MB,体积适中,便于拷贝到 U 盘或内网分发。目前已有 3205 人学习下载。按依赖顺序执行安装即可完成离线部署,省去逐条排查依赖关系的时间,也便于在无外网的生产、教学或实验环境中复现统一的编译环境。

1. 一个 zip 包引出的版本问题:ubuntu18.04 上的 gcc7 到底该怎么落地

上周有位同事拿了个ubuntu18.04gcc.zip过来,说机器在内网、连不上软件源,让我帮他把 gcc7 装上。他先在 Windows 上把 zip 解压了一遍,传进 Ubuntu,然后unzip展开,在终端里执行第一个.deb,屏幕上立刻出现一屏dependency problems prevent configuration,他当时就以为包坏了。其实包没坏,问题在于 ubuntu18.04 上装 gcc7 这件事有前置条件:系统自带的 gcc-7 已经是 7.5.0,平时很少需要额外安装;真正容易出问题的是在没有网络的环境里用 dpkg 手动安装一套互相依赖的 deb 包,而安装顺序、alternatives 优先级和-f install补依赖,每一步都可能卡住。这篇记录就是我在这类离线机器上反复装过几轮后留下的操作顺序,适合要固定 gcc7 版本做构建复现、或者内网机器无法访问软件源的人照着走。

2. 装前把账算清:gcc7 在 ubuntu18.04 上的版本来源与依赖清单

动手前先把「这套东西从哪来、装到哪、依赖谁」三件事定下来,比装到一半再回头查要省事得多。ubuntu18.04 这个发行版本身发布时就把 gcc-7 作为默认编译器,版本停在 7.5.0,/usr/bin/gcc通过 alternatives 指向gcc-7。所以拿到一个 gcc7 的压缩包时,先别急着解压,先想清楚你要的是「补上缺失的 gcc7」还是「把系统默认版本钉死在 7」,这两件事的操作路径完全不同。

2.1 三种来源的取舍:源内安装、zip 里的 deb、源码编译

同样叫「装 gcc7」,三条路各有各的代价,选错路会让后面所有步骤都变别扭。

第一种是走 apt:sudo apt-get install gcc-7 g++-7。这是最省事的,依赖由 apt 自己解,装完 alternatives 也会自动注册好。限制是必须有可用的软件源,内网机器、被裁剪过的镜像、或者源里只剩 main 而缺 universe 的情况都用不了。第二种就是手里这个 zip:里面是一组已经编译好的 deb 包,配合dpkg -i离线落地,不依赖网络,但依赖关系得自己扛。第三种是下源码./configure && make,我不太推荐在 18.04 上为了一个 7.5.0 去编译,因为要先把 GMP、MPFR、MPC 三个数学库准备好,编译一次十几到几十分钟,机器内存小一点还会被cc1plus吃满。

我一般的判断标准很朴素:能联网就走 apt;完全离线、或者构建流水线要求所有机器二进制一致,就走 zip 里的 deb;只有需要改--enable-languages、--with-arch这类编译选项时才考虑源码。zip 这条路的优势在于版本固定,同一个包铺到十台机器上,gcc -v的输出一模一样,排查构建差异时省掉一大截猜测。

2.2 解包后先看清结构:用 dpkg-deb 读包再动手

拿到压缩包,第一步不是解压到当前目录,而是先看清单。zip 里通常混着.deb、可能的install.sh、以及一份说明文件,先unzip -l列一下,确认没有多层目录嵌套,也确认没有混进 arm64 或 i386 的包。

# 不解压,先看压缩包里的文件清单和体积 unzip -l ubuntu18.04gcc.zip # 正式解到一个独立目录,避免和家目录里的东西混在一起 mkdir -p ~/offline/gcc7 && cd ~/offline/gcc7 unzip ~/ubuntu18.04gcc.zip -d . ls -lh

unzip -l的输出重点看两列:文件名和长度。如果看到gcc-7_7.5.0-3ubuntu1~18.04_amd64.deb这种命名,amd64就是架构标识,必须和dpkg --print-architecture的输出一致,否则dpkg -i会直接抛package architecture (arm64) does not match system (amd64)。长度那一列用来粗判包是否完整,一个几百 KB 的gcc-7主包基本可以认定是下载中断留下的残包。

解开之后,对每个 deb 读一遍元信息,比直接装要稳:

# 读单个包的版本、架构、依赖,只看前 25 行足够 dpkg-deb -I gcc-7_*.deb | head -25 # 看这个包会把文件铺到哪些路径 dpkg-deb -c gcc-7_*.deb | head -20 # 一次性把目录里所有包的依赖打出来,方便对照系统已装的东西 for f in *.deb; do echo "== $f"; dpkg-deb -f "$f" Depends; done

dpkg-deb -I输出里的Depends字段是后面排查的关键,它列出的包名带版本约束,比如libgcc-7-dev (= 7.5.0-3ubuntu1~18.04),这种带等号的强约束意味着版本差一个字符都会导致配置失败。dpkg-deb -c则是看文件落点,重点确认/usr/bin/gcc-7、/usr/lib/gcc/x86_64-linux-gnu/7/这两处,前者是编译器驱动,后者是头文件和内部库,缺一个都编不出东西。

2.3 依赖与磁盘、编译内存的底线

把包里所有Depends汇总去重,再跟dpkg -l的已装列表对一遍,缺什么心里就有数了。一套完整的 gcc7 相关包,职责大致如下:

包名作用缺失时的典型报错
gcc-7-base基础文件、版权与文档后续所有包依赖解析失败
cpp-7C 预处理器配置阶段报依赖 cpp-7 未满足
gcc-7C 编译器驱动与 cc1/usr/bin/gcc-7不存在
libgcc-7-dev头文件、crt 目标文件、静态库cannot find crtbegin.o
g++-7C++ 编译器驱动与 cc1plusg++: command not found
libstdc++-7-devC++ 标准库头文件与链接用 .sobits/stdc++.h: No such file

磁盘方面,这一套解开安装后大概占几百 MB,/usr/lib/gcc和/usr/include/c++是大头,装之前用df -h /usr看一眼,留出 1 GB 比较安心。内存方面,gcc7 本身不挑,但用它编大文件时cc1plus是内存消耗的主要部分,2 GB 内存的机器编单个超过五千行的 C++ 文件容易触发 OOM,这种情况要么加 swap,要么拆文件,和编译器版本无关。

提示:如果机器上已经存在 gcc-7 包,dpkg -i会走升级或重装逻辑,不会报错,但也不会给你任何提示。装之前先dpkg -l | grep -E 'gcc-7|g\+\+-7'看一眼现状,避免以为「装上了」其实是「本来就有」。

3. 用 dpkg 把它装上:从解压到配置完成的四步

前面把包看清楚了,这一章是实际落地的部分。dpkg 和 apt 最大的区别在于,apt 会在装之前把依赖顺序算好,dpkg 则是你说装哪个就装哪个,缺依赖就停在半配置状态。所以整个流程要按「先底层后上层、先 base 后具体」的顺序推,中间任何一步报错都先解决再往下走,不要连着往下灌命令。

3.1 解压与落盘路径:别放在 /tmp

路径这件事看着无关紧要,实际影响挺大。放在/tmp里,有些系统配置了tmpfs或者定时清理,装到一半重启,源文件没了,后面--configure -a想补都没法补。放在家目录下的固定目录最稳妥,装完之后这个目录还能留作回滚用的备份。

# 固定落盘位置,权限给普通用户即可,dpkg 安装时才需要 root mkdir -p ~/offline/gcc7-deb unzip -o ubuntu18.04gcc.zip -d ~/offline/gcc7-deb cd ~/offline/gcc7-deb # 确认架构一致,输出应为 amd64 dpkg --print-architecture # 确认系统当前已装的 gcc 版本,作为切换前后的对照 gcc --version | head -1

unzip -o的-o是覆盖已有文件不询问,重复解包时省掉一堆交互。解压目录我用gcc7-deb,和系统目录区分开,后面执行dpkg -i ~/offline/gcc7-deb/*.deb时通配符不会误伤别的文件。如果你习惯把包放在/opt,记得chmod 755保证 root 能读到,有些机器家目录是 700 的,sudo 下反而读不到。

3.2 dpkg -i 的安装顺序与批量装法

真正的安装命令只有一条,但顺序有讲究。dpkg 在批量安装时其实会尝试自己排序,多数情况下dpkg -i *.deb一次就能过,出问题的往往是 base 包和 dev 包之间的关系没理顺。我的习惯是分两批:先装不会依赖别人的,再装其余的。

# 第一批:base 包和预处理器,这两个几乎不依赖同批其他包 sudo dpkg -i gcc-7-base_*.deb cpp-7_*.deb # 第二批:编译器本体、C++ 驱动、运行时开发包一起上 sudo dpkg -i gcc-7_*.deb g++-7_*.deb libgcc-7-dev_*.deb libstdc++-7-dev_*.deb # 如果包的命名不统一,直接用通配符一把梭,dpkg 会自行排序 sudo dpkg -i ~/offline/gcc7-deb/*.deb

前两条命令的意图是降低依赖问题的排查难度:gcc-7-base是整个依赖链的根,cpp-7只依赖 base 和 libc6,这两个装上之后,剩下的包报依赖错误的概率会小很多。第三条是兜底做法,当你确认目录里所有 deb 都是同一批构建产物时,一条通配符最省事,dpkg 内部会按依赖关系重排,装完再把没配置成功的挑出来单独处理。

安装过程里最该盯的是输出里有没有Errors were encountered while processing:这一段。没有这一行,说明所有包都进到了installed状态,可以跳到 3.4 收尾;有这一行,后面的包名就是没能配置成功的,先不要继续装别的,转去 3.3 处理依赖。

3.3 依赖没齐的两条补救路径:apt -f install 与手动补包

报dependency problems prevent configuration的时候,先别慌,用dpkg -l看状态列。状态是iU(已解包未配置)或者iF(配置失败),都说明文件已经铺到磁盘上了,只差配置这一步,不需要重装。

# 看哪些包卡在未配置状态,ii 是正常,iU / iF 是有问题 dpkg -l | grep -E 'gcc-7|g\+\+-7|cpp-7' | grep -v '^ii' # 路径一:有可用源时,让 apt 把缺的依赖补齐并重新配置 sudo apt-get -f install -y # 路径二:完全离线时,从包里找缺的那个 deb 单独补,例如缺 libisl sudo dpkg -i libisl*.deb sudo dpkg --configure gcc-7

apt-get -f install的-f是 fix broken 的意思,它会读 dpkg 的状态库,把所有未满足的依赖列出来,能下的下、能配的配。这条路的前提是有源,内网机器通常会卡在这里,报一堆Failed to fetch。这时候走路径二:把 2.2 步拿到的Depends清单对着dpkg -l逐条核,缺哪个就单独dpkg -i那个包,再dpkg --configure 包名触发配置脚本。

如果报错信息里出现的是libc6-dev版本过低这类系统级依赖,说明机器的系统补丁落后于这批 deb 的构建基线,这种包我不建议硬装,容易出现装了 gcc7 却把 libc6 弄坏、连ls都起不来的情况。稳妥做法是先把系统apt-get update && apt-get upgrade到同一基线,或者换一份和当前系统补丁级别匹配的包。

3.4 收尾:dpkg --configure -a 与 apt-mark hold

装完之后做两件收尾的事:把可能残留的未配置包全部配置掉,然后把版本锁住,防止某次apt upgrade把 gcc7 悄悄换掉。

# 把所有处于未配置状态的包重新跑一遍配置脚本 sudo dpkg --configure -a # 确认安装结果,三个包都应该在 ii 状态 dpkg -l | grep -E '^ii\s+(gcc-7|g\+\+-7|libstdc\+\+-7-dev)' # 锁住版本,避免后续系统升级动它 sudo apt-mark hold gcc-7 g++-7 cpp-7 libgcc-7-dev libstdc++-7-dev

dpkg --configure -a的-a表示全部,它会重新执行每个未配置包的 postinst 脚本。这一步经常被跳过,结果是dpkg -l里看着有 gcc-7,但/usr/bin/gcc-7的软链没建、man 文档没生成,后面 alternatives 注册时会找不到目标文件。

apt-mark hold是我在离线机器上的固定习惯。锁住之后再apt-mark showhold就能看到列表,哪天要升级系统先apt-mark unhold解开。不锁的后果我遇到过:一次例行升级把 libstdc++-7-dev 换成更新版本,头文件路径没变但内部 ABI 符号变了,之前编好的产物跑起来报符号找不到,查了半天才定位到是升级导致的。

4. 版本切换与共存:update-alternatives 的参数怎么给

包装上不等于系统默认用的就是它。ubuntu 的编译器是通过 alternatives 机制做的软链,/usr/bin/gcc本身是个指向/etc/alternatives/gcc的链接,再指到具体版本。这一章说清楚优先级怎么给、什么时候该用手动软链、以及怎么在不改系统默认的前提下临时用 gcc7。

4.1 用 alternatives 建组:优先级与 slave 链接

先说结论:gcc、g++、gcov应该作为一组来管理,用--slave把它们绑在一起,这样切一次全切,不会出现gcc是 7 而g++是 9 的尴尬局面。

# 注册 gcc7 到 alternatives,priority 按主版本号乘 10 给 sudo update-alternatives --install /usr/bin/gcc gcc /usr/bin/gcc-7 70 \ --slave /usr/bin/g++ g++ /usr/bin/g++-7 \ --slave /usr/bin/gcov gcov /usr/bin/gcov-7 \ --slave /usr/bin/gcc-ar gcc-ar /usr/bin/gcc-ar-7 \ --slave /usr/bin/gcc-nm gcc-nm /usr/bin/gcc-nm-7 # 交互式选择当前使用的版本 sudo update-alternatives --config gcc # 非交互场景下直接指定,适合写进部署脚本 sudo update-alternatives --set gcc /usr/bin/gcc-7

--install的四个位置参数分别是:链接路径、组名、实际文件路径、优先级。优先级数字大的在自动模式下胜出,所以我把 gcc-7 给 70、gcc-8 给 80、gcc-9 给 90,这样新装的版本会自动接管,需要钉死 7 的时候用--set手动指定,逻辑清晰不用记。--slave后面跟两组参数,前者是链接路径,后者是实际文件;slave 的特点是跟着 master 走,master 一切它全切,这是保证gcc和g++版本一致的关键。

--config gcc会列出所有候选版本和当前选择,输入编号回车即可。这一步在脚本里不能用,因为它需要交互输入;自动化部署一律用--set,指定完整路径,写错路径会直接报错而不是静默失败,比编号可靠。

4.2 手动软链的做法和它的代价

有些教程会教你直接ln -sf /usr/bin/gcc-7 /usr/bin/gcc,看起来很直接,但我一般不用。原因有三个:一是它会覆盖 alternatives 建的链接,之后update-alternatives --config gcc显示的当前选择就和实际不符,排查时容易被误导;二是系统升级重装 gcc 包时,postinst 会把链接重新指回去,你的修改静默失效,而你不知道;三是没有 slave 机制,g++还得单独再链一次,漏了就是 C 编得过 C++ 编不过。

只有在一种情况下我会考虑手动软链:容器镜像里 alternatives 机制被裁剪掉了,update-alternatives命令不存在或者/etc/alternatives目录是空的。这种场景下用软链是没办法的办法,但要在 Dockerfile 里写清楚,并且同时链gcc、g++、cc、c++四个入口,cc和c++这两个名字很多 Makefile 会直接调。

# 仅在 alternatives 不可用时使用,四个入口一起链,别只链 gcc ln -sf /usr/bin/gcc-7 /usr/bin/gcc ln -sf /usr/bin/g++-7 /usr/bin/g++ ln -sf /usr/bin/gcc-7 /usr/bin/cc ln -sf /usr/bin/g++-7 /usr/bin/c++

4.3 编译期指定 CC/CXX:不改系统默认也能用 gcc7

多数时候我们并不想动系统默认版本,尤其是这台机器上还跑着别的构建任务时。这种情况下根本不用碰 alternatives,直接在构建命令前加环境变量就行,Makefile 和 CMake 都会优先读这两个变量。

# 单次构建临时指定编译器 CC=/usr/bin/gcc-7 CXX=/usr/bin/g++-7 make -j4 # CMake 项目在 configure 阶段就把编译器钉死,避免缓存污染 cmake -S . -B build -DCMAKE_C_COMPILER=/usr/bin/gcc-7 \ -DCMAKE_CXX_COMPILER=/usr/bin/g++-7 # 确认 CMake 真的用上了,输出里应能看到 gcc-7 的路径 grep -E 'CMAKE_(C|CXX)_COMPILER:' build/CMakeCache.txt

CC和CXX必须写绝对路径。写gcc-7这种相对形式也能工作,但如果 PATH 里有多个 gcc-7,优先级不确定;写/usr/bin/gcc-7就完全没有歧义。CMake 那一行要注意的是,编译器只在第一次 configure 时生效,后面改CMakeCache.txt里的值不会重新检测,必须删掉build目录重来,这一点我在一个跨平台项目上反复遇到过。

-j4里的并行度按 CPU 核数给,nproc查一下即可。用 gcc7 编大项目时并行度不要开太满,每个 cc1plus 进程都要吃几百 MB 内存,8 核机器给-j6比-j8稳,留点余量给系统。

5. 避坑与排查:五条装 gcc7 时的血泪记录

下面这几条都是我在离线机器上真实撞过的,现象、原因、解决按顺序写,遇到对得上的直接照着处理。

5.1 装完 gcc --version 还是老版本

现象:dpkg -l | grep gcc-7显示ii,/usr/bin/gcc-7也存在,但gcc --version输出的还是 9 或者别的版本。

原因:alternatives 没注册,或者注册了但优先级低于现有版本,自动模式下没选上。也有一种情况是/usr/bin/gcc被上一次手动软链改过,指向了一个不存在的文件,update-alternatives认为链接不归它管。

解决:先ls -l /usr/bin/gcc看它指向哪,正常应指向/etc/alternatives/gcc。如果不是,说明被手动改过,用sudo update-alternatives --install重新注册后再--config gcc选一次。注册完update-alternatives --query gcc能看到所有候选和当前值,这一步比猜快得多。

5.2 dpkg -i 报依赖错误,包停在 unpacked

现象:安装输出末尾出现Errors were encountered while processing: gcc-7,dpkg -l里 gcc-7 状态是iU。

原因:同批 deb 里的某个依赖包没装,或者装了但版本号不满足=强约束。gcc 系列包的 Depends 里大量使用精确版本号,包和包之间必须严格同批。

解决:dpkg-deb -f gcc-7_*.deb Depends把依赖列出来,逐条对着dpkg -l核版本号。差版本的那条,从包里找对应 deb 装上,再sudo dpkg --configure gcc-7。有源的情况下sudo apt-get -f install -y一步到位,离线机器只能手动核。

5.3 编译 C++ 报找不到 stdc++ 或 bits/stdc++.h

现象:C 代码编得过,C++ 报fatal error: bits/stdc++.h: No such file or directory,或者链接阶段报cannot find -lstdc++。

原因:只装了gcc-7,没装g++-7和libstdc++-7-dev。这两个是独立包,gcc-7的依赖里不含它们,因为 C 编译器不需要 C++ 的东西。

解决:补装g++-7和libstdc++-7-dev,前者提供cc1plus和驱动,后者提供/usr/include/c++/7/下的头文件和链接用的.so符号链接。装完ls /usr/include/c++/7/bits/stdc++.h确认文件在,再编一次。

5.4 dpkg 被中断,之后所有安装都失败

现象:执行任何apt或dpkg命令都报dpkg was interrupted, you must manually run 'dpkg --configure -a',或者报锁文件被占用。

原因:上一次安装中途被打断,可能是 Ctrl+C、可能是 SSH 断连,也可能是机器重启。dpkg 的状态库里有未完成的记录,它会拦住所有后续操作防止状态错乱。

解决:按提示执行sudo dpkg --configure -a。如果报的是锁文件/var/lib/dpkg/lock-frontend被占用,先ps aux | grep -E 'apt|dpkg'确认没有活着的进程,再删锁文件。锁文件被占也可能是有 unattended-upgrades 在后台跑,等它跑完即可,不要硬删。

5.5 程序运行时报 GLIBCXX_3.4.22 not found

现象:用 gcc7 编出来的程序,在另一台机器上跑,启动时报version 'GLIBCXX_3.4.22' not found。

原因:程序链接的是编译机上的libstdc++.so.6,运行机器的系统库里没有对应版本的 C++ ABI 符号。这个问题和 gcc 装得对不对没关系,是运行时库版本不一致。

解决:strings /usr/lib/x86_64-linux-gnu/libstdc++.so.6 | grep GLIBCXX看运行机器支持到哪个版本号。最简单的做法是静态链接-static-libstdc++ -static-libgcc,代价是体积变大。另一种是随程序分发一份匹配的.so并用LD_LIBRARY_PATH指定,但要注意加载顺序,别把系统库顶掉。

6. 装完怎么验证:三个层次的检查,别只看 gcc --version

gcc --version只证明驱动能跑,证明不了头文件、运行时库、链接器都齐全。我一般分三层验:第一层是驱动和路径,第二层是 C 和 C++ 的实际编译链接,第三层是编译产物能不能在目标机器上加载。三层都过,才算这套 gcc7 真的落地了。

# 第一层:驱动、版本号、内部搜索路径 gcc -dumpversion # 应输出 7 gcc -v 2>&1 | tail -5 # 看 Configured with 那行确认构建参数 gcc -print-search-dirs | head -3 # 确认库搜索路径在 /usr/lib/gcc/.../7 下 # 第二层:真实编译一个 C 和一个 C++ 程序 cat > /tmp/t.c <<'EOF' #include <stdio.h> int main(void) { printf("c ok %d\n", __GNUC__); return 0; } EOF gcc -Wall -O2 /tmp/t.c -o /tmp/t && /tmp/t cat > /tmp/t.cpp <<'EOF' #include <iostream> #include <vector> #include <algorithm> int main() { std::vector<int> v{3, 1, 2}; std::sort(v.begin(), v.end()); // 模板实例化,验证头文件完整 for (int x : v) std::cout << x << ' '; std::cout << '\n'; return 0; } EOF g++ -std=c++17 -Wall -O2 /tmp/t.cpp -o /tmp/tpp && /tmp/tpp

第一层的-dumpversion输出的是主版本号,gcc7 上就是7;-v的末尾几行会打印Configured with:,从里面能看出--with-arch、--enable-languages这些构建选项,离线包和源码编译出来的差别通常就藏在这一行。第二层的 C++ 样例特意用了vector和sort,是为了逼编译器去实例化模板、去读/usr/include/c++/7/bits/下的头文件,只写个hello world是验不出头文件包缺失的。

第三层是很多人漏掉的,尤其是在有部署环节的场景里:

检查项命令期望结果
运行时库版本strings /usr/lib/x86_64-linux-gnu/libstdc++.so.6 | grep GLIBCXX_3.4.22有输出,说明 ABI 符号在
二进制依赖ldd /tmp/tpp没有not found行
对象文件架构file /tmp/tpp显示x86-64且dynamically linked
C++17 文件系统g++ -std=c++17 fs.cpp -lstdc++fsgcc7 必须显式加-lstdc++fs,不加会报undefined reference

表格最后一行是 gcc7 的一个时代特征,std::filesystem在 GCC 7 里还放在stdc++fs这个独立库里,GCC 9 之后才并进主库。这个差异会导致同一份代码在 7 上编不过、在 9 上没事,反过来也一样,写构建脚本时用版本判断把-lstdc++fs加上,比事后查链接错误省事。

全部验完,我习惯把这次的版本信息记进机器上的一个备注文件,gcc -v 2>&1 | tail -3 >> ~/offline/env-notes.txt,连同包的来源和解压目录一起写。半年后回来查「这台机器为什么编出来的东西和别的不一样」,翻这个文件三十秒就能定位。

从那以后,我每次在一台离线机器上装完编译器,都会强制把这三层验证走一遍,尤其是第三层的ldd和GLIBCXX检查——这两步花不了两分钟,却能挡掉上线之后才发现符号找不到的那类问题。希望帮到你。

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