资讯动态

CentOS7 源码编译升级 GCC 11 并正确生效实践

发布时间:2026/10/27 3:56:19 来源:尧图企业网站定制
1. 为什么系统自带的 gcc 版本总是“不够用”如果你在一台 centOS7 机器上编译过稍微新一点的 C 项目大概率遇到过这类报错error: stdc17 is not a namespace-name、undefined reference to std::filesystem、或者 configure 阶段直接甩给你一句C17 compiler required。这时候你敲一下gcc -v会看到版本号停在4.8.5而这个版本发布于 2015 年连 C14 都支持不全C17 更是想都别想。这就是本文要解决的核心问题在 centOS7 上把 gcc / g 换成足够新的版本并且让整个系统在编译时正确调用新的编译器。这里的关键词不是“安装”而是“安装完之后让它真正生效”。我见过太多人装完了新版本gcc -v还是 4.8.5然后开始怀疑人生——问题不在安装在环境变量的优先级和系统默认路径的覆盖关系。centOS7 的 yum 源里最高只有gcc 4.8.5这是它作为长期支持发行版的定位决定的稳定性优先软件栈老得可以当文物。想用新版编译器只有三条路升级系统不现实很多生产环境动不了、找第三方 yum 源如 devtoolset 系列思路是并行安装不覆盖系统默认、源码编译最通用也最能锻炼人。这三条路各有各的坑下面会一条条说清楚。适合谁来读需要在 centOS7 上编译现代 C 项目、搭建开发环境、或者给老服务器续命的后端和 C 开发者。如果你只是偶尔写个 Hello World系统自带的 4.8.5 完全够用不必折腾。但只要你的项目用了std::filesystem、std::optional、协程、concepts 这些特性升级就是刚需。下面这套流程我在多台 centOS7 机器上跑过包括物理机和容器环境踩过的坑都会写出来。先说一个很多人忽略的前提升级 gcc 不是替换而是并存。系统里有大量工具链比如内核模块、某些系统库、yum 自身的依赖是拿 4.8.5 编译的你如果把 4.8.5 直接删掉换成新版轻则某些命令报错重则系统起不来。所以正确思路是新版本装到/usr/local或者独立目录通过PATH和LD_LIBRARY_PATH控制调用顺序系统默认的那份保持原样不动。2. 动手前的体检确认系统状态与依赖完整性2.1 先看清楚你手上是什么牌动手之前先做三件事确认系统版本、确认当前 gcc 版本、确认磁盘空间。别嫌啰嗦我遇到过在容器里操作、结果发现是 centos7 的精简镜像缺一堆编译依赖白折腾一小时。cat /etc/redhat-release gcc --version g --version df -h /usr/local/usr/local至少留出5GB空间。gcc 源码包解压后大约 1GB编译过程产生的中间文件.o、.s会有好几个 G完整安装完大概占 2~3GB。空间不够的话make跑到 90% 挂掉那种感觉相当难受。2.2 依赖装齐能省掉后面 80% 的报错centOS7 最小化安装默认缺少编译 gcc 所需的几个关键库。这里一次性装全yum install -y gcc gcc-c make cmake \ glibc-devel glibc-headers kernel-headers \ libmpc-devel mpfr-devel gmp-devel \ zlib-devel gzip bzip2 bzip2-devel \ wget tar这里每个包都有明确用途不是无脑堆砌依赖包作用缺失后的典型报错gmp-devel / mpfr-devel / mpc-devel高精度数学运算库gcc 内部大量使用configure: error: Building GCC requires GMP 4.2glibc-devel / glibc-headersC 标准库头文件fatal error: stdio.h: No such filekernel-headers内核头文件编译某些系统调用相关代码时失败bzip2-devel / zlib-devel压缩库gcc 处理某些格式时依赖configure 阶段检测失败make / cmake构建工具make: command not found注意gmp-devel这类库在 centos7 里版本偏老gmp 6.0.0对 gcc 8 到 11 都够用。但如果你要上 gcc 12 以上源码编译时需要--with-gmp之类的手动指定或者先在本地编译一份新版 GMP否则 configure 会报版本不足。另外gcc 自举编译是内存敏感的。官方建议每核 2GB 内存起步我实测4 核 4GB 的虚拟机编译 gcc 11 会失败报virtual memory exhausted: Cannot allocate memory升到 8GB 才跑通。如果你的机器内存小于 4GB要么加 swap要么减少并行度make -j1这点后面会细说。3. 三条路线的取舍devtoolset 与源码编译怎么选3.1 devtoolset最省事但版本有天花板Software Collections 里的 devtoolset 系列是最省心的方案本质是并行安装一整套工具链用scl enable临时切换环境完全不影响系统默认的 4.8.5。yum install -y centos-release-scl yum install -y devtoolset-11-gcc devtoolset-11-gcc-c devtoolset-11-binutils scl enable devtoolset-11 bash gcc --version # 此时显示 11.x优点很明确十分钟装完依赖自动解决卸载干净。缺点也很明确版本停在 devtoolset-11不同镜像源里最多到 12 左右且不保证可用而且要每次手动scl enable或者写进~/.bashrc。更麻烦的是scl enable只对当前 shell 生效某些通过 systemd、cron 或者 CI runner 调起的进程不会继承这个环境编译时还是用回 4.8.5这个坑相当隐蔽。还有一点devtoolset 装出来的 gcc其内部的--prefix是指向/opt/rh/的如果项目里用 CMake 写了find_package去探测编译器路径或者用CMAKE_C_COMPILER硬编码/usr/bin/gcc那就完全绕过了 devtoolset编译出来一堆莫名其妙的链接错误。这种时候只能手动改 CMake 变量或者用scl enable之后重新 configure。我的判断标准如果你的目标是“在现有项目上跑通构建”devtoolset 足够如果是“搭建自己的开发环境、需要长期维护、或者需要 12 以上版本”源码编译更可控。下面重点讲源码编译因为它是通用解法也不受镜像源是否可用的限制这一点在内网环境里尤其重要。3.2 源码编译的版本选择别追最新写这篇文章时 gcc 已经出到 14但我不建议在 centos7 上装最新版。原因有三个第一个是glibc 版本约束。centos7 的 glibc 是 2.17而新版本 gcc 的运行时libstdc对 glibc 的符号有要求。装 gcc 13、14 时很容易遇到GLIBC_2.27 not found这类运行时错误编译出来的程序拿到别的机器上跑不起来。第二个是编译时长。gcc 源码编译是自举过程先用系统 gcc 编出一个 stage1再用 stage1 编 stage2最后用 stage2 编 stage3。这个过程耗时随版本非线性增长。gcc 9 在 8 核机器上大约 40 分钟gcc 13 可能要 1.5 小时以上。第三个是C ABI 变动。gcc 11 之后对 C17/20 的支持做了不少调整某些用了旧特性写法比如std::auto_ptr、register关键字的遗留代码在新编译器上会直接编译失败需要改代码。我的推荐是gcc 10 或 11。这两个版本对 C17 支持完整支持std::filesystem、std::optional、结构化绑定、if constexpr 等对 C20 支持大部分核心特性且在 centos7 上编译成功率最高社区踩坑记录也最全。如果项目确实需要 C20 的协程或 concepts再上 gcc 12。3.3 下载源的选择与校验源码从官方镜像或者国内镜像下载都行注意下gcc-11.x.tar.xz而不是.gz前者体积小一半左右cd /usr/local/src wget https://mirrors.tuna.tsinghua.edu.cn/gnu/gcc/gcc-11.4.0/gcc-11.4.0.tar.xz # 如果镜像站不通换用 ftp.gnu.org 官方源下载完成后务必校验这不是形式主义。我遇到过压缩包下载不完整、解压报xz: (stdin): Unexpected end of input的情况也见过内网代理缓存返回了错误页面、文件大小看起来正常实则是 HTML 的情况ls -lh gcc-11.4.0.tar.xz # 应该在 130MB 左右 xz -t gcc-11.4.0.tar.xz # 校验压缩包完整性xz -t通过再解压。如果大小明显偏小比如几 KB那就是下载失败了别硬着头皮往下走。4. 依赖库的预编译gcc 编译链里最容易被跳过的一步4.1 为什么必须在 configure 之前跑 download_prerequisitesgcc 源码目录里有个脚本contrib/download_prerequisites作用是把 GMP、MPFR、MPC、ISL 这几个数学库下载到源码树里并创建软链接。gcc 的 configure 和 make 会自动使用这些本地的库而不是系统库。这一步不能跳过。原因很简单centos7 自带的 GMP 是 6.0.0MPFR 是 3.1.1而 gcc 11 的 configure 脚本会检查gmp.h里的版本宏要求GMP 4.2 以上、MPFR 2.4.2 以上。虽然系统版本理论上满足但实际编译时链接的库版本和头文件版本可能不一致比如装了多个 GMP 版本导致undefined reference to __gmpz_...一堆符号缺失。cd /usr/local/src/gcc-11.4.0 ./contrib/download_prerequisites脚本跑完目录里会出现gmp-6.2.1、mpfr-4.1.0、mpc-1.2.0、isl-0.24这些目录和对应软链接。如果网络不通脚本会失败这时候有两个办法手动下载这四个包放到源码根目录注意目录名必须和脚本预期一致比如gmp-6.2.1而不是gmp否则 configure 找不到。如果已经有系统安装的较新版本可以用--with-gmp/path/to/gmp、--with-mpfr、--with-mpc显式指定路径。脚本执行成功的话最后会打印All prerequisites downloaded successfully.。看到这句话再往下走。4.2 建一个独立的构建目录gcc不支持在源码目录直接 configure准确说是不建议会在源码树里生成大量中间文件污染源码后续想重新编译还得清理。正确做法是建一个平级的构建目录mkdir -p /usr/local/src/gcc-build cd /usr/local/src/gcc-build这个目录建议放在源码同级的路径下不要放在/tmp里——/tmp在某些系统配置下会被自动清理编译到一半文件没了排查起来很痛苦。5. configure 参数逐项拆解每个开关都在解决什么问题这一步是整个流程里最需要“知其所以然”的部分。很多人抄一条命令就跑跑完出问题也不知道是哪个参数的问题。我把常用参数的逻辑拆开讲/usr/local/src/gcc-11.4.0/configure \ --prefix/usr/local/gcc-11.4.0 \ --enable-languagesc,c,objc,obj-c,fortran \ --disable-multilib \ --enable-shared \ --enable-threadsposix \ --with-system-zlib \ --disable-bootstrap逐个说--prefix/usr/local/gcc-11.4.0安装路径带版本号好处是将来升级到 gcc 12 时可以和 11 并存切换只改环境变量。不要装到/usr或/usr/local根目录会和系统已有的/usr/bin/gcc冲突造成混乱。--enable-languagesc,c只编译需要的语言前端。默认会编译所有语言包括 Java 的 gcj、Go 的 gccgo、Ada 的 gnat编译时间翻倍磁盘占用也翻倍。只写 C 和 C 能把编译时间压到 40 分钟左右。如果项目里有 Fortran 代码科学计算常见加上fortran。--disable-multilib只生成 64 位代码不生成 32 位库。centos7 的绝大多数应用都是 64 位的开 multilib 会让编译时间增加约 30%还会引入 32 位 libc 的依赖问题。除非你有明确的 32 位编译需求比如编译老式游戏或嵌入式工具否则关掉。--enable-shared生成动态链接的 libstdc。不开这个的话只产出静态库编译出来的程序体积会大很多且某些依赖动态库的第三方包找不到符号。--enable-threadsposix指定线程模型为 POSIX。默认值在 Linux 上一般就是 posix但显式写出来更稳妥避免某些精简环境检测异常。--with-system-zlib使用系统的 zlib 而不是源码里自带的。系统 zlib 版本够用省一点编译时间。如果系统 zlib 太老导致编译失败去掉这个参数让它用内置版本。--disable-bootstrap这个参数争议最大。bootstrap 机制是用刚编出来的编译器再编一遍自己验证编译器自身的正确性。开 bootstrap 意味着编译三遍时间三倍但质量更可靠。我个人的建议生产环境首次搭建时开 bootstrap去掉--disable-bootstrap确认工具链可靠如果只是本地开发用、或者时间紧张用--disable-bootstrap只编一遍编译速度能快一半以上。提示configure 阶段会输出大量检测信息最后必须看到configure: creating ./config.status和config.status: creating Makefile才算成功。如果中途报configure: error: ...看错误信息里提到的库或工具装齐再重来不要试图跳过。configure 跑完可以看一眼日志确认没有遗漏grep -i error config.log | head -20正常情况下应该没有输出。6. 编译与安装并行度、内存和时间的平衡术6.1 make -j 的取值不是核数越多越好这是实战里最容易出问题的地方。很多人看到 8 核就make -j8结果内存爆掉进程被杀。gcc 编译的单个编译单元尤其是.cc文件内存消耗可以达到 1.5~2GB-j并行度越高峰值内存越大。经验公式-j取值为min(核数, 内存GB数 / 2)。机器配置建议 -j预期耗时gcc 11含 bootstrap2 核 4GB-j23~4 小时可能内存不足4 核 8GB-j41.5~2 小时8 核 16GB-j640~60 分钟16 核 32GB-j1225~35 分钟内存实在不够先加 swap# 临时加 4GB swap fallocate -l 4G /swapfile chmod 600 /swapfile mkswap /swapfile swapon /swapfile free -h # 确认 swap 已生效注意 swap 只解决内存不足导致的 OOM 崩溃用 swap 编译会拖慢速度磁盘 IO 成为瓶颈但比编译到一半被杀要强。编译命令cd /usr/local/src/gcc-build make -j4这一步耗时最长建议挂nohup或者用screen/tmux跑避免 SSH 断连导致前功尽弃nohup make -j4 make.log 21 tail -f make.log编译过程中可以另开终端看日志出错的话make.log里会有明确的Error 1和出错位置。常见的编译错误及原因报错信息原因处理virtual memory exhausted内存不足降低 -j 或加 swaperror while loading shared libraries: libisl.so.15ISL 库路径不对检查 download_prerequisites 是否成功或用 LD_LIBRARY_PATH 指定fatal error: gmp.h: No such fileGMP 头文件缺失重新跑 download_prerequisitescannot find -lstdc链接器路径问题检查--with-system-zlib后是否清理了构建目录6.2 make install 与权限细节make install这一步会把编译产物装到--prefix指定的目录大约几分钟。如果装到/usr/local下需要 root 权限如果是普通用户把--prefix指到$HOME/.local/gcc-11.4.0也可以但要对应调整后续的环境变量路径。装完之后验证/usr/local/gcc-11.4.0/bin/gcc --version /usr/local/gcc-11.4.0/bin/g --version注意这里是用绝对路径调用。如果直接敲gcc --version显示的还是 4.8.5说明环境变量还没配好这是正常现象下一步就是解决它。7. 让新版本真正生效PATH、动态库与编译期路径7.1 PATH 的优先级与环境变量写法安装完不生效是这篇标题下最高频的问题。原因是/usr/bin在PATH里的位置比新装的目录靠前。解决办法有几种各有适用场景。方案一写进~/.bashrc或/etc/profile.d/# /etc/profile.d/gcc-11.sh对所有用户生效 export GCC_HOME/usr/local/gcc-11.4.0 export PATH$GCC_HOME/bin:$PATH export LD_LIBRARY_PATH$GCC_HOME/lib64:$LD_LIBRARY_PATH关键是$GCC_HOME/bin要放在$PATH前面而不是追加到末尾。写成export PATH$PATH:$GCC_HOME/bin就完全无效因为系统会先找到/usr/bin/gcc。验证source /etc/profile.d/gcc-11.sh which gcc # 应该指向 /usr/local/gcc-11.4.0/bin/gcc gcc --version # 显示 11.4.0方案二用 alternatives 管理多版本alternatives --install /usr/bin/gcc gcc /usr/local/gcc-11.4.0/bin/gcc 100 \ --slave /usr/bin/g g /usr/local/gcc-11.4.0/bin/g \ --slave /usr/bin/gcov gcov /usr/local/gcc-11.4.0/bin/gcov alternatives --config gcc # 交互式选择版本这个方案的好处是切换干净、系统级生效、不依赖 shell 配置缺点是会覆盖/usr/bin/gcc的符号链接某些依赖系统 gcc 版本的工具比如某些内核模块编译可能出问题。生产服务器上我更倾向方案一因为不改变系统默认链接出问题好回退——把 profile 文件删掉重登即可。7.2 动态库路径libstdc 的版本共存问题新版 gcc 编译出的程序依赖新版libstdc.so.6。如果把LD_LIBRARY_PATH指向了新版本的 lib64那么所有程序包括系统自带的都会优先加载新版 libstdc。新版本 libstdc 是向后兼容的正常情况下系统程序能正常跑但如果某些程序对新版 libstdc 里的符号解析有异可能出问题。更稳妥的做法是不全局改 LD_LIBRARY_PATH而是在编译时通过 rpath 把路径写进可执行文件g -stdc17 main.cpp -o main \ -Wl,-rpath,/usr/local/gcc-11.4.0/lib64 \ -L/usr/local/gcc-11.4.0/lib64或者用 CMake 管理时在CMakeLists.txt里设置set(CMAKE_C_COMPILER /usr/local/gcc-11.4.0/bin/gcc) set(CMAKE_CXX_COMPILER /usr/local/gcc-11.4.0/bin/g) set(CMAKE_EXE_LINKER_FLAGS -Wl,-rpath,/usr/local/gcc-11.4.0/lib64)这样编出来的程序在任何环境都能找到正确的库不依赖环境的LD_LIBRARY_PATH。这一点在部署到容器或其他机器时特别重要——否则你会遇到“本地跑得好好的换台机器就libstdc.so.6: version GLIBCXX_3.4.29 not found”。如果确实遇到了这个报错有两个方向一是把新版 libstdc 一起打包带走或者放在程序同级的 lib 目录配合 rpath 使用二是静态链接 libstdcg -stdc17 main.cpp -o main -static-libstdc -static-libgcc静态链接会让二进制体积增大几 MB但换来的是零依赖适合分发场景。7.3 检查编译产物到底用了哪个编译器装完之后做一次“认证测试”确认新版本真的在干活# 测试 C17 特性是否可用 cat /tmp/test17.cpp EOF #include iostream #include filesystem #include optional int main() { std::optionalint opt 42; std::filesystem::path p /tmp; std::cout opt *opt path p std::endl; return 0; } EOF g -stdc17 /tmp/test17.cpp -o /tmp/test17 /tmp/test17能正常输出opt42 path/tmp说明编译器、标准库、运行库这条链路全通了。再检查一下 libstdc 的版本strings /usr/local/gcc-11.4.0/lib64/libstdc.so.6 | grep GLIBCXX_3.4.2 | tail -5应该能看到GLIBCXX_3.4.29这类高版本符号。如果只有到3.4.19对应 gcc 4.8说明编译器用的还是系统老库检查LD_LIBRARY_PATH和 rpath。8. 踩坑实录那些让我重跑过编译过程的细节8.1 编译成功但链接失败路径里的版本号写错了有一次装完 gcc 11编译项目时一直报undefined reference to std::filesystem::...。查了半天原因是我在LD_LIBRARY_PATH里写的是/usr/local/gcc-11.4.0/lib而实际库文件在lib64下。因为--disable-multilib只生成 64 位库lib目录可能不存在或是空的。排查思路先用find确认库到底在哪find /usr/local/gcc-11.4.0 -name libstdc.so*然后用ldd看可执行文件依赖解析到了哪里ldd /tmp/test17 | grep stdc如果显示not found就是路径问题如果指向了/usr/lib64/libstdc.so.6老版本就是优先级问题。8.2-stdc17有效但-stdc20报错版本没选对很多项目默认写-stdc20如果装的是 gcc 9会报unrecognized command-line option -stdc20。gcc 9 只支持到-stdc2aC20 的早期草案名。gcc 10 开始才正式支持-stdc20。这提醒我们选版本要跟着项目的编译选项走。项目里用的std版本决定了下限项目要求的 std最低 gcc 版本备注c114.8系统自带就够c145.1建议 7 以上更稳c177 完整、8 完善推荐 9 以上c2010 部分、11 较全推荐 11c2313 以上centos7 上慎用8.3 编译成功但运行时崩溃glibc 版本的地雷这个坑最隐蔽。在新版 gcc 上编译出的程序拿到另一台机器跑时报GLIBC_2.28 not found。原因是你这台机器的 glibc 可能不是原生的 2.17而是被其他软件升级过如果源码编译的 gcc 链接了这个高版本 glibc 的符号产物就依赖了高版本。检查方法ldd --version | head -1 # 确认 glibc 版本 objdump -T /tmp/test17 | grep GLIBC_ | awk {print $5} | sort -u看产物依赖的最高 glibc 版本符号。如果只是GLIBC_2.2.5、GLIBC_2.17这类说明没问题如果出现了高于 2.17 的就要评估部署环境是否支持。结论在 centos7 上编译出来的东西如果要在同版本或更老的环境跑一定要检查 glibc 符号依赖。跨环境部署时用容器打包是更省心的方案——把编译环境和运行环境一起打包从根源上避免这类问题。8.4 编译到一半make报错说找不到cc1pluscc1plus是 g 的实际编译前端。报错cannot execute cc1plus通常是编译过程被打断、中间产物不完整导致的。find /usr/local/src/gcc-build -name cc1plus如果存在但无法执行可能是权限或者动态库路径问题如果不存在说明编译没完成清理后重来cd /usr/local/src/gcc-build make clean # 或者直接 rm -rf * 重建目录切记不要在编译中途 CtrlC 之后直接make install那会装进去一个半成品工具链后续所有编译都会出怪问题且极难排查。8.5 环境变量配好了CMake 还是用老编译器这是 CMake 的缓存机制导致。CMake 首次 configure 会把编译器路径缓存进CMakeCache.txt之后即使你改了PATH它也固执地用缓存里的。解决办法rm -rf build mkdir build cd build cmake -DCMAKE_C_COMPILER/usr/local/gcc-11.4.0/bin/gcc \ -DCMAKE_CXX_COMPILER/usr/local/gcc-11.4.0/bin/g \ ..或者养成习惯在CMakeLists.txt开头就显式指定编译器路径注意这个设置必须在project()之前set(CMAKE_C_COMPILER /usr/local/gcc-11.4.0/bin/gcc) set(CMAKE_CXX_COMPILER /usr/local/gcc-11.4.0/bin/g) project(MyProject)写成set(CMAKE_C_COMPILER ...)放在project()之后会静默无效——CMake 不报错但用的还是旧的这个坑我踩过不止一次。8.6 一个容易被忽略的细节libstdc 的 ABI 兼容如果项目里链接了第三方预编译库.so或.a用新版 gcc 编译自己的代码时可能遇到undefined reference。原因是新版 gcc 默认启用 C11 ABI_GLIBCXX_USE_CXX11_ABI1而老库是用旧 ABI 编的std::string的内部布局不同导致符号对不上。报错长这样undefined reference to foo::bar(std::__cxx11::basic_string...)解决办法有两种编译时加-D_GLIBCXX_USE_CXX11_ABI0用旧 ABI兼容老库但放弃新 ABI 的性能优化。让第三方库用新 ABI 重编推荐但需要源码。判断当前用的哪种 ABInm -C /path/to/libfoo.so | grep std::__cxx11有__cxx11标记的就是新 ABI。把两边的 ABI 统一问题就解决了。9. 收尾几点实在的经验整套流程跑下来耗时主要花在 make 上其他步骤加起来不到十分钟。我的建议是编译前把能想到的都准备好编译中别去动它。gcc 自举编译对系统状态比较敏感中途改环境变量、装软件、动/tmp都可能让编译失败。再补几个零散但有用的点如果机器是多个人共用装到/usr/local/gcc-11.4.0之后一定要在文档里写清楚环境变量的配置方式否则下一个人上来还是用 4.8.5然后找你抱怨。有条件的话把编译好的/usr/local/gcc-11.4.0整个目录打包存一份约 2GB。下次装同版本直接从包解压几分钟搞定比重编译一小时划算得多。注意打包前用make install-strip或者手动strip一下二进制能省不少体积。升级到新版本之后旧的 4.8.5 别急着删。系统里有些脚本、包管理工具、甚至某些 shell 扩展依赖它。留着它靠 PATH 优先级控制使用是成本最低的做法。如果项目后续要频繁重建不妨在 CI 里检出 centos7 的基础镜像后就预装好新版本编译器把编译脚本和环境变量固定下来避免每次都在环境上耗时间。最后说个容易被忽略的心态问题升级编译器这件事大部分人卡住不是因为步骤难而是因为遇到报错不知道从哪查。我自己的习惯是看到报错先确认三件事现在到底在用什么编译器绝对路径、用的是哪个标准库ldd 查、命令里的路径有没有写错版本号、lib 还是 lib64。这三个问题定位清楚八成的编译问题都能自己解决。

读完文章,也想定制专属网站?

尧图设计师 24 小时内与您沟通定制方案

免费获取报价 →
↑