
簡(jiǎn)介在無(wú)法連接互聯(lián)網(wǎng)的服務(wù)器、學(xué)校機(jī)房或邊緣設(shè)備中搭建編譯器工具鏈常因缺少依賴而失敗。這份面向紅帽系列Linux 6系統(tǒng)的GCC離線安裝包共包含十二個(gè)文件十一份軟件安裝包與一份安裝腳本。其中十一份安裝包覆蓋基礎(chǔ)編譯器、C編譯器、預(yù)處理程序、系統(tǒng)頭文件與內(nèi)核頭文件等關(guān)鍵組件并已處理版本匹配關(guān)系安裝腳本則負(fù)責(zé)自動(dòng)檢查環(huán)境、解包并完成安裝使運(yùn)維人員無(wú)需逐條執(zhí)行命令即可完成部署。軟件包整體壓縮后約二十四兆字節(jié)體積小巧便于使用移動(dòng)介質(zhì)拷入內(nèi)網(wǎng)。目前已有五百五十六人學(xué)習(xí)使用特別適合需要在內(nèi)網(wǎng)或受限網(wǎng)絡(luò)環(huán)境中搭建開(kāi)發(fā)環(huán)境的系統(tǒng)管理員與開(kāi)發(fā)者同時(shí)通過(guò)查看安裝包內(nèi)各文件的依賴結(jié)構(gòu)也能幫助初學(xué)者理解編譯器集合的組成和軟件包管理的基本思路。1. gcc 離線安裝一臺(tái)內(nèi)網(wǎng)裸機(jī)的剛需前幾天幫某公司機(jī)房做環(huán)境交付機(jī)器是全新的最小化安裝的 Linux沒(méi)有外網(wǎng)權(quán)限gcc --version直接提示 command not found而所有業(yè)務(wù)系統(tǒng)都需要編譯源碼。更麻煩的是不是一臺(tái)機(jī)器而是三十臺(tái)同配置的機(jī)器都得統(tǒng)一裝好同樣的工具鏈。我手頭沒(méi)有光盤(pán)也沒(méi)有內(nèi)網(wǎng) yum 鏡像只能靠一個(gè)離線包把整個(gè) gcc 編譯鏈端過(guò)去。這就是這類“gcc 離線安裝包腳本”資源的典型用途把 gcc 本體以及所有依賴打包成 RPM 集合再通過(guò)腳本在內(nèi)網(wǎng)批量安裝。適合運(yùn)維工程師、實(shí)施人員、測(cè)試環(huán)境搭建者以及所有被內(nèi)外網(wǎng)隔離折磨過(guò)的人。2. 在聯(lián)網(wǎng)機(jī)器上收集 rpmyumdownloader 與 reposync 的取舍2.1 為什么不能只拷貝 gcc 的單個(gè) rpm很多人第一次做離線安裝會(huì)直接在一臺(tái)有網(wǎng)的機(jī)器上yum install -y gcc然后跑到/var/cache/yum里翻那個(gè) RPM 文件拷到內(nèi)網(wǎng)去裝。結(jié)果是rpm -ivh gcc-xxx.rpm報(bào)一堆依賴缺失libmpc.so.3()(64bit) is needed、libmpfr.so.4()(64bit) is needed、cpp x.x.x is needed。gcc 從來(lái)不是一個(gè)孤立軟件包它跟 cpp、binutils、glibc-devel、gmp、mpfr、mpc、isl 這些包綁定得很緊只拷本體等于只帶了發(fā)動(dòng)機(jī)沒(méi)帶輪胎。所以第一步不是下載而是先想清楚需要哪些包。在一個(gè)標(biāo)準(zhǔn)的 x86_64 的 CentOS/RHEL 類系統(tǒng)上gcc 的工具鏈至少包含這些gcc、gcc-c、gcc-gfortran可選、cpp、binutils、glibc-devel、libstdc-devel、libgcc、libgomp以及被依賴的gmp、mpfr、mpc、isl。這里還不算 kernel-headers如果機(jī)器要編譯內(nèi)核模塊還得補(bǔ)上kernel-devel但那是另一個(gè)話題不是 gcc 的基本盤(pán)。2.2 用 yumdownloader 收集指定包及自動(dòng)依賴我的常規(guī)做法是用yumdownloader它只下載不安裝也不會(huì)去動(dòng)當(dāng)前系統(tǒng)的包狀態(tài)。優(yōu)點(diǎn)是干凈、可控缺點(diǎn)是必須手動(dòng)把依賴列全漏一個(gè)在內(nèi)網(wǎng)就會(huì)卡住。下面的命令在聯(lián)網(wǎng)機(jī)器上執(zhí)行# 先安裝 yum-utils提供 yumdownloader 命令 yum install -y yum-utils # 建一個(gè)目錄后面所有 rpm 都放這里 mkdir -p /tmp/gcc-offline-pkgs # 下載 gcc 及常用工具鏈加 --resolve 自動(dòng)解析依賴 yumdownloader --destdir/tmp/gcc-offline-pkgs --resolve \ gcc gcc-c gcc-gfortran cpp binutils \ glibc-devel libstdc-devel libgcc libgomp \ gmp-devel mpfr-devel mpc-devel isl-devel這里--resolve是關(guān)鍵參數(shù)它會(huì)像yum install一樣做依賴解析把缺的依賴包一起拉到 destdir 里。跟直接yum install不同它不會(huì)安裝只負(fù)責(zé)下載。--destdir指定輸出目錄建議用絕對(duì)路徑后面做本地 repo 時(shí)路徑不容易寫(xiě)錯(cuò)。gcc-gfortran如果業(yè)務(wù)不需要 Fortran 編譯器完全可以去掉能少拉一堆依賴。gmp-devel、mpfr-devel這一類帶-devel的包主要是給以后要手工編譯其他軟件時(shí)提供頭文件和.so軟鏈如果純裝 gcc 自身有些并非強(qiáng)制但為了一個(gè)包一次到位我一般都會(huì)收進(jìn)去。2.3 用 reposync 拉整個(gè) base 倉(cāng)庫(kù)的備選方案如果內(nèi)網(wǎng)機(jī)器數(shù)量多、后續(xù)還要裝別的軟件yumdownloader就不夠用了因?yàn)槟忝垦b一個(gè)軟件都得重新收集一次。這種時(shí)候建議改用reposync直接把遠(yuǎn)程的 base/updates 倉(cāng)庫(kù)同步到本地內(nèi)網(wǎng)服務(wù)器再配合createrepo生成倉(cāng)庫(kù)元數(shù)據(jù)等于在內(nèi)網(wǎng)搭建了一個(gè)迷你 yum 源。命令如下# 安裝 createrepo 和 yum-utils yum install -y createrepo yum-utils # 只同步 base 倉(cāng)庫(kù)到本地目錄帶元數(shù)據(jù) reposync -p /tmp/yum-mirror --repoidbase --download-metadata # 為鏡像目錄生成倉(cāng)庫(kù)索引 createrepo /tmp/yum-mirror--repoidbase指定同步哪個(gè)倉(cāng)庫(kù)可以用yum repolist查看當(dāng)前系統(tǒng)啟用的倉(cāng)庫(kù) ID。--download-metadata會(huì)同步 primary、filelists 這類元數(shù)據(jù)生成后就能直接做成內(nèi)網(wǎng) repo 源。注意reposync會(huì)把整個(gè)倉(cāng)庫(kù)幾十 GB 都拉下來(lái)如果只是裝個(gè) gcc 沒(méi)必要但它確實(shí)是一勞永逸的方案。如果磁盤(pán)緊張還可以用--filter或者只同步幾個(gè)特定包但那樣語(yǔ)法會(huì)復(fù)雜不少不適合新手折騰。2.4 收集完成后的自檢清單下載完之后別急著打包先做一遍清點(diǎn)不然到了內(nèi)網(wǎng)才發(fā)現(xiàn)缺包來(lái)回折騰很浪費(fèi)時(shí)間。我一般會(huì)跑這幾條檢查# 檢查數(shù)量、大小和架構(gòu) ls -lh /tmp/gcc-offline-pkgs/*.rpm | wc -l du -sh /tmp/gcc-offline-pkgs # 確認(rèn)都是 x86_64沒(méi)有混入 i686 或 noarch rpm -qp --qf %{NAME}-%{VERSION}-%{RELEASE}.%{ARCH}\n /tmp/gcc-offline-pkgs/*.rpm | grep -v x86_64\|noarch || echo 架構(gòu)全部一致 # 檢查簽名信息確保沒(méi)拉壞包 rpm -K /tmp/gcc-offline-pkgs/*.rpm 2/dev/null | grep -i OK | wc -l這個(gè)檢查非常關(guān)鍵。之前我遇到過(guò)一臺(tái) 64 位系統(tǒng)yumdownloader 因?yàn)槟硞€(gè)依賴的編譯環(huán)境問(wèn)題意外把 i686 的 glibc-devel 也拉了進(jìn)來(lái)內(nèi)網(wǎng)安裝時(shí) RPM 對(duì)架構(gòu)非常敏感i686 和 x86_64 同時(shí)出現(xiàn)會(huì)導(dǎo)致依賴判斷錯(cuò)亂。所以檢查架構(gòu)那一步最好每次都跑。另外用rpm -K校驗(yàn)簽名時(shí)如果系統(tǒng)沒(méi)有導(dǎo)入對(duì)應(yīng) GPG 公鑰會(huì)提示 NOKEY那種情況只要確認(rèn) sha256 校驗(yàn)通過(guò)即可不必過(guò)分緊張.3. 安裝腳本設(shè)計(jì)本地 repo 源與冪等安裝3.1 rpm -Uvh 直接硬裝為什么容易翻車把 rpm 包拷到內(nèi)網(wǎng)后最常見(jiàn)的主觀想法是rpm -Uvh /tmp/pkgs/*.rpm一把梭。但這樣做的失敗率極高因?yàn)閞pm -Uvh不會(huì)做依賴解析它只是逐個(gè)安裝遇到依賴缺失就報(bào)錯(cuò)退出。更麻煩的是gcc 依賴鏈里有循環(huán)情況比如gcc依賴mpc、mpc依賴mpfr、mpfr依賴gmp表面看是一長(zhǎng)串但實(shí)際用rpm -Uvh *.rpm一起裝時(shí)RPM 內(nèi)部會(huì)嘗試解決順序問(wèn)題多數(shù)時(shí)候能成但一旦其中一個(gè)包版本未滿足另外包的精確要求整個(gè)事務(wù)就會(huì)回滾連已裝好的也全部撤銷。運(yùn)氣壞的時(shí)候還會(huì)把 glibc 相關(guān)包動(dòng)到弄完系統(tǒng)直接起不來(lái)那已經(jīng)不是翻車是翻溝里了。所以我給配套腳本設(shè)計(jì)的核心思路是先建本地 yum 倉(cāng)庫(kù)再讓 yum 去解決依賴。yum 是完整的依賴解析器比人肉排序可靠得多。3.2 用 createrepo 把 rpm 目錄變成 yum 源在離線機(jī)器上先把包解壓到固定目錄然后用createrepo生成元數(shù)據(jù)。這里有一個(gè)細(xì)節(jié)離線機(jī)器的軟件源里必須提前有createrepo這個(gè)工具否則你連源都建不出來(lái)。所以在收集階段我就把createrepo和它的依賴python-deltarpm、libxml2-python加進(jìn)了 yumdownloader 的清單里。# 假設(shè)離線包在 /opt/gcc-pkgs 下 cd /opt/gcc-pkgs # 生成 repodata 目錄 createrepo . # 寫(xiě) repo 文件到 /etc/yum.repos.d/ cat /etc/yum.repos.d/gcc-local.repo EOF [gcc-local] nameGCC Local Repository baseurlfile:///opt/gcc-pkgs enabled1 gpgcheck0 EOF # 清緩存并驗(yàn)證 repo 是否生效 yum clean all yum repolistcreaterepo .會(huì)在當(dāng)前目錄生成repodata/文件夾里面是 primary.xml.gz 等元數(shù)據(jù)。repo 文件里的gpgcheck0是因?yàn)殡x線包沒(méi)有對(duì)應(yīng)的 GPG 公鑰如果設(shè)成 1yum 會(huì)拒絕安裝并報(bào)錯(cuò)。file://協(xié)議指向本地目錄注意路徑必須和包實(shí)際位置一致寫(xiě)成file:///opt/gcc-pkgs是三個(gè)斜杠少了就加載不到。3.3 腳本冪等安裝、日志記錄與退出碼寫(xiě)安裝腳本時(shí)我堅(jiān)持三個(gè)原則可以重復(fù)跑、跑完有日志、失敗有明確退出碼。很多離線安裝腳本都是寫(xiě)死的命令裝過(guò)一次再跑就亂套沒(méi)有日志排查時(shí)全靠猜這種腳本我不愿意交付給別人。下面這個(gè)是精簡(jiǎn)版的腳本骨架#!/bin/bash # gcc 離線安裝腳本 # 用法: ./install_gcc_offline.sh [pkgs_dir] PKG_DIR${1:-/opt/gcc-pkgs} LOG_FILE/var/log/gcc-offline-install.log # 判斷是否已安裝過(guò) gcc if rpm -q gcc /dev/null 21; then echo [$(date)] gcc 已安裝跳過(guò) | tee -a $LOG_FILE exit 0 fi # 檢查 repo 文件是否存在 if [ ! -f /etc/yum.repos.d/gcc-local.repo ]; then echo [$(date)] 未找到 gcc-local.repo請(qǐng)先配置本地源 | tee -a $LOG_FILE exit 1 fi # 用 yum 安裝自動(dòng)解析依賴 yum install -y gcc gcc-c gcc-gfortran 21 | tee -a $LOG_FILE # 驗(yàn)證安裝結(jié)果 if rpm -q gcc gcc-c /dev/null 21; then echo [$(date)] gcc 工具鏈安裝成功 | tee -a $LOG_FILE exit 0 else echo [$(date)] 安裝失敗檢查 /var/log/gcc-offline-install.log | tee -a $LOG_FILE exit 1 fi這個(gè)腳本的邏輯很直白開(kāi)頭用rpm -q gcc判斷是否已安裝避免重復(fù)裝一遍中間用yum install而不是rpm -Uvh讓 yum 解析本地 repo 里的依賴最后再驗(yàn)證一次 gcc 是否真的可用。tee -a把命令輸出同時(shí)打到終端和日志文件這樣出問(wèn)題可以回看日志。${1:-/opt/gcc-pkgs}是給路徑留了一個(gè)參數(shù)位默認(rèn)值是/opt/gcc-pkgs如果你把包解壓到別處執(zhí)行時(shí)把路徑傳進(jìn)去就行。3.4 批量部署時(shí)的參數(shù)化修改那臺(tái)服務(wù)器是三十臺(tái)機(jī)器我一般不會(huì)一臺(tái)臺(tái)跑而是配合 ansible 的 copy 模塊把 rpms 目錄和腳本分發(fā)下去再批量執(zhí)行。腳本里唯一要改的就是PKG_DIR的默認(rèn)路徑如果內(nèi)網(wǎng)每臺(tái)機(jī)器的授權(quán)目錄不同建議改成從配置文件讀路徑而不是硬編碼。還一個(gè)重要參數(shù)是yum install那一行的包名列表如果不需要 gfortran刪掉即可。這個(gè)腳本盡量保持單文件、零依賴因?yàn)樗旧砭褪请x線安裝用的如果它再依賴別的東西就成雞生蛋問(wèn)題。4. 依賴鏈拆解gcc 從 rpm 到源碼編譯所需的完整包清單4.1 gcc 的依賴樹(shù)底層庫(kù)的層級(jí)關(guān)系gcc 的依賴不像普通軟件那樣只是一條線而是分三層。最底層是被 gcc 運(yùn)行庫(kù)直接調(diào)用的數(shù)學(xué)庫(kù)包括gmp大整數(shù)運(yùn)算、mpfr浮點(diǎn)運(yùn)算、mpc復(fù)數(shù)運(yùn)算這三個(gè)在 gcc 編譯階段就必須存在它們的.so文件會(huì)被 gcc 自身鏈接。再上層是isl這是一個(gè)整數(shù)線性規(guī)劃庫(kù)GCC 在做循環(huán)優(yōu)化和并行優(yōu)化時(shí)依賴它。最上面才是gcc、cpp、gcc-c這些編譯前端。如果只是用yum install gccyum 會(huì)把這些底層庫(kù)自動(dòng)拉進(jìn)來(lái)但離線手工收集時(shí)很多人會(huì)漏掉isl因?yàn)樗诶系?CentOS 6 里甚至不是獨(dú)立包而是被編進(jìn) gcc 的內(nèi)部目錄。到了 CentOS 7/8 上才把它拆成獨(dú)立isl包。所以收集時(shí)不要想當(dāng)然按文檔里常見(jiàn)的依賴列表來(lái)最好用yumdownloader --resolve自動(dòng)抓抓完再用rpm -qpR逐個(gè)驗(yàn)證一遍.so是否被滿足、依賴包是否都在本地。4.2 編譯期依賴與運(yùn)行期依賴的差異另一個(gè)容易錯(cuò)的重點(diǎn)是區(qū)分編譯期和運(yùn)行期。glibc-devel提供的是stdio.h、stdlib.h這些頭文件它是編譯 C 程序時(shí)才需要的運(yùn)行時(shí)程序用的是/lib64/libc.so.6這是 glibc 包提供的。所以在離線機(jī)器上如果你只裝了 gcc 而沒(méi)裝glibc-develgcc -v能正常輸出版本號(hào)但編譯hello.c時(shí)會(huì)報(bào)stdio.h: No such file or directory。這不是 gcc 壞了是缺開(kāi)發(fā)頭文件。同樣的道理適用于libstdc-devel。gcc-c包本身含 g 編譯器和基礎(chǔ)運(yùn)行庫(kù)但標(biāo)準(zhǔn)模板庫(kù)STL的頭文件在libstdc-devel里。很多人在內(nèi)網(wǎng)編譯 C 項(xiàng)目時(shí)報(bào)iostream: No such file就是他只收了gcc-c忘了libstdc-devel。至于編譯后的程序跑到另一臺(tái)機(jī)器上還需要什么那是另一套ldd檢查的思路不是離線安裝 gcc 重點(diǎn)。4.3 版本匹配不能用新版 RPM 包覆蓋舊系統(tǒng)在聯(lián)網(wǎng)機(jī)器上收集 rpm 時(shí)有個(gè)隱含風(fēng)險(xiǎn)聯(lián)網(wǎng)機(jī)器如果比內(nèi)網(wǎng)機(jī)器系統(tǒng)版本新比如聯(lián)網(wǎng)機(jī)是 CentOS 8內(nèi)網(wǎng)機(jī)是 CentOS 7拉下來(lái)的 gcc RPM 拿到內(nèi)網(wǎng)是裝不上的因?yàn)?RPM 打包時(shí)依賴的 glibc 版本高于內(nèi)網(wǎng)系統(tǒng)自帶的東西。裝的時(shí)候會(huì)直接報(bào)libc.so.6(GLIBC_2.18)(64bit) is needed然后拒絕安裝。收集安裝包前先確認(rèn)好目標(biāo)內(nèi)網(wǎng)系統(tǒng)的版本最好的做法是找一臺(tái)和離線機(jī)器完全同版本、同小版本的聯(lián)網(wǎng)機(jī)器來(lái)采集或者在內(nèi)網(wǎng)里隨便選一臺(tái)同樣系統(tǒng)的機(jī)器先臨時(shí)聯(lián)網(wǎng)用它自己的 yum 拉包再斷網(wǎng)。實(shí)在找不到同版本的也可以退而求其次用--releasever指定系統(tǒng)版本去收集比如# 在聯(lián)網(wǎng)機(jī)器上指定系統(tǒng)版本收集防止拉到太新的包 yumdownloader --destdir/tmp/gcc-pkgs --releasever7 --resolve \ gcc gcc-c glibc-devel libstdc-devel--releasever7會(huì)讓 yum 以 CentOS 7 的倉(cāng)庫(kù)視圖去解析依賴這樣收集到的 RPM 版本匹配 CentOS 7。如果連這個(gè)參數(shù)都不加默認(rèn)用你當(dāng)前系統(tǒng)的版本裝到低版本系統(tǒng)上就會(huì)出現(xiàn)上面的 GLIBC 錯(cuò)誤。常見(jiàn)依賴包對(duì)應(yīng)系統(tǒng)版本如下表格可以在寫(xiě)離線部署文檔時(shí)直接抄用目標(biāo)系統(tǒng)gcc 默認(rèn)版本glibc 版本注意點(diǎn)CentOS 74.8.52.17gcc 較老C11 支持不完整CentOS 88.5.02.28支持 C17注意 repo 源差異Ubuntu 18.047.5.02.27包格式為 deb不適用于 rpm 腳本5. 離線安裝避坑五條翻車經(jīng)歷與排查方法5.1 現(xiàn)象rpm -ivh 報(bào)內(nèi)存不足安裝到一半被殺原因同一時(shí)間把所有 rpm 用一條命令提交RPM 會(huì)為每個(gè)包都做事務(wù)檢查內(nèi)存占用疊加在低配的 1G 內(nèi)存機(jī)器上直接 OOM。這是我在某項(xiàng)目的 512M 小機(jī)器上踩過(guò)的坑三十多個(gè)包一起rpm -ivh進(jìn)度到一半進(jìn)程被系統(tǒng) kill連已裝的包也全部回滾。解決不要一次性rpm -Uvh *.rpm改用yum installyum 是逐個(gè)處理事務(wù)的內(nèi)存峰值低得多。如果一定要用 rpm把安裝批次拆成每次 5-10 個(gè)包且先裝底層庫(kù)再裝 gcc 本體。5.2 現(xiàn)象yum install gcc提示 Nothing to do但 gcc 命令確實(shí)不存在原因本地 repo 配置文件baseurl指向的路徑不對(duì)或者目錄里沒(méi)有repodata子目錄。yum 在 repo 加載失敗時(shí)不會(huì)明確報(bào)錯(cuò)而是把該 repo 靜默忽略最后 Nothing to do。解決用yum repolist看看gcc-local是否出現(xiàn)在啟用的倉(cāng)庫(kù)列表里。沒(méi)出現(xiàn)就檢查 repo 文件里的路徑和file://寫(xiě)法路徑尾部不要加多余的/。另外當(dāng)心 tar 解壓時(shí)如果帶著頂層目錄包實(shí)際在/opt/gcc-pkgs/gcc-pkgs/下repo 指向/opt/gcc-pkgs就空了。5.3 現(xiàn)象gcc 能編譯 C 程序但編譯 C 時(shí)報(bào)找不到 iostream原因gcc 本體和 gcc-c 是分離的gcc包只帶 C 編譯器和基礎(chǔ)庫(kù)。g命令可能根本不存在或者存在但缺少 STL 頭文件。解決確認(rèn)離線包清單里有g(shù)cc-c和libstdc-devel。驗(yàn)證方法rpm -q gcc-c如果已裝但仍然報(bào)錯(cuò)檢查g -print-search-dirs輸出里的 include 路徑是否有對(duì)應(yīng)的/usr/include/c目錄。5.4 現(xiàn)象編譯時(shí)報(bào)cannot find crtbegin.o或crt1.o原因這是 binutils 和 glibc-devel 的問(wèn)題不是 gcc 本體。crt1.o和crtbegin.o分別位于 glibc-devel 和 gcc 包內(nèi)部?jī)烧呷笔Ь蜁?huì)缺鏈接啟動(dòng)文件。有人為了省空間故意去掉 glibc-devel結(jié)果就是這個(gè)錯(cuò)。解決把glibc-devel加進(jìn)包里并確認(rèn) gcc 安裝目錄下lib/gcc/x86_64-redhat-linux/{version}/crtbegin.o確實(shí)存在。有時(shí)候還需要binutils的ld命令可用離線時(shí)記得把binutils包也帶上。5.5 現(xiàn)象腳本第二次運(yùn)行時(shí)把 gcc 降級(jí)到了舊版本原因腳本里用了rpm -Uvh直接裝舊版 RPM或者yum install時(shí)本地 repo 里的包版本低于已裝版本yum 默認(rèn)不會(huì)降級(jí)但 rpm -Uvh 會(huì)強(qiáng)制覆蓋為低版本。內(nèi)網(wǎng)機(jī)器如果被升級(jí)過(guò)再跑腳本就會(huì)出現(xiàn)版本倒退。解決腳本開(kāi)頭加rpm -q gcc判斷已裝則直接跳過(guò)。我在腳本骨架里已經(jīng)寫(xiě)了這個(gè)邏輯執(zhí)行exit 0前會(huì)先檢查避免誤傷。6. 裝完別急著收工版本驗(yàn)證與一鍵卸載回退6.1 三步驗(yàn)證編譯環(huán)境是否真正可用裝完之后光看rpm -qa | grep gcc不算完編譯器這種工具必須跑一次真實(shí)編譯才算驗(yàn)證通過(guò)。我一般固定走這三個(gè)步驟缺一不可# 第一步確認(rèn) gcc/g 版本在 PATH 里且版本匹配 gcc --version g --version # 第二步寫(xiě)最小 C 程序編譯運(yùn)行 echo #include stdio.h /tmp/test.c echo int main() { printf(gcc offline ok\n); return 0; } /tmp/test.c gcc /tmp/test.c -o /tmp/test_c /tmp/test_c # 第三步寫(xiě)最小 C 程序編譯運(yùn)行驗(yàn)證 STL 頭文件可用 echo #include iostream /tmp/test.cpp echo int main() { std::cout g offline ok std::endl; return 0; } /tmp/test.cpp g /tmp/test.cpp -o /tmp/test_cpp /tmp/test_cpp注意第二步和第三步必須都跑很多離線安裝 C 的驗(yàn)證能過(guò)死在 C 上。gcc --version看到的版本號(hào)只說(shuō)明編譯器本身能運(yùn)行不代表頭文件、鏈接庫(kù)都齊全。跑到std::cout這一行才把libstdc-devel和頭文件路徑全部驗(yàn)證到了。6.2 留一條回退路徑卸載腳本與包清單快照離線安裝最怕的不是裝不上而是裝到一半系統(tǒng)環(huán)境被搞亂。以前我在一臺(tái)機(jī)器上裝新版本 gcc它把系統(tǒng)原有的libstdc.so.6覆蓋掉結(jié)果所有依賴舊版本 ABI 的程序全部啟動(dòng)報(bào)錯(cuò)那真是災(zāi)難。從那以后我每次離線安裝前都會(huì)先執(zhí)行一次包清單快照把改動(dòng)前的 rpmdb 狀態(tài)保存下來(lái)安裝完成后再生成一份差異清單留著做回退依據(jù)# 安裝前快照 rpm -qa --qf %{NAME}-%{VERSION}-%{RELEASE}.%{ARCH}\n /tmp/rpmdb-before.txt # 安裝后快照 rpm -qa --qf %{NAME}-%{VERSION}-%{RELEASE}.%{ARCH}\n /tmp/rpmdb-after.txt # 找出新增和升級(jí)的包 diff -u /tmp/rpmdb-before.txt /tmp/rpmdb-after.txt | grep ^ | cut -c2-把 diff 出來(lái)的結(jié)果送到卸載腳本里變成rpm -e命令列表。注意卸載順序要反過(guò)來(lái)先卸載 gcc 和 gcc-c再考慮動(dòng)底層庫(kù)但底層庫(kù)盡量不要回滾因?yàn)槠渌蜒b的軟件可能已經(jīng)依賴新版本。這套快照方案不能保證百分百還原但至少給了你一份明確的改動(dòng)記錄排查和回退都有跡可循。另外一個(gè)小技巧安裝完成之后可以把gcc --version的完整輸出、g --version的完整輸出連同編譯測(cè)試的返回碼一起寫(xiě)進(jìn)交付文檔里這樣后面接手的人一眼就能看出工具鏈狀態(tài)不用自己再搭一套環(huán)境重新驗(yàn)證一遍。從那以后我每次部署完 gcc 都強(qiáng)制走一遍這個(gè)三步驗(yàn)證流程并把版本號(hào)記成文件放到/etc/gcc-install-info.txt里這樣后面再出問(wèn)題至少不用猜測(cè)機(jī)器上裝的是哪個(gè)版本希望這套方法和避坑記錄能幫到你。本文還有配套的精品資源點(diǎn)擊獲取