離線安裝g++:依賴處理與本地源搭建實戰(zhàn))
剛拿到一臺Kylin初始系統(tǒng)的服務(wù)器網(wǎng)絡(luò)是隔離的內(nèi)網(wǎng)連yum倉庫都連不出去第一個任務(wù)就是離線配置g。這事兒聽起來像一條命令的事但真正在離線環(huán)境里做過的都知道光是“離線”兩個字就能把人折騰夠嗆。我這次把整個過程完整走了一遍從識別系統(tǒng)版本、準(zhǔn)備離線包、處理依賴到最后驗證編譯踩了不少坑也摸出幾條高效路徑。這篇文章就把完整流程和關(guān)鍵經(jīng)驗寫下來給同樣在內(nèi)網(wǎng)機房、離線部署環(huán)境里折騰Kylin的人一個可以直接抄作業(yè)的參考。1. 先分清Kylin的Debian血統(tǒng)和RPM血統(tǒng)這決定了離線安裝姿勢1.1 兩條命令識別系統(tǒng)的“血統(tǒng)”Kylin V10和普通的CentOS/Ubuntu不太一樣市面上常見的是兩個大系列。一個是服務(wù)器版銀河麒麟高級服務(wù)器操作系統(tǒng)V10版本號里常帶SP1/SP2/SP3軟件管理走yum/dnf包后綴是.rpm整體對標(biāo)RHEL/CentOS生態(tài)。另一個是桌面版銀河麒麟桌面操作系統(tǒng)V10軟件管理走apt/dpkg包后綴是.deb整體對標(biāo)Debian生態(tài)。問題在于這兩個系列離線配置g的方法完全不一樣網(wǎng)上搜到的教程如果不先看版本直接照搬很容易裝到一半就報一堆依賴錯誤。所以第一步不是找安裝包而是確認這臺機器到底屬于哪套體系。最簡單的辦法是執(zhí)行cat /etc/os-release看輸出里的 NAME、VERSION、ID字段。出現(xiàn)“Kylin Server”或“Kylin Advanced Server”字樣基本走RPM體系出現(xiàn)“Kylin Desktop”大概率走DEB體系。如果還不放心再跑一條which yum || which dnf which apt-get哪個命令存在就用哪套體系。這一步花30秒能省后面1小時。我見過有人拿桌面版的思路去服務(wù)器版上搞結(jié)果rpm數(shù)據(jù)庫一路報錯最后只能重裝系統(tǒng)。1.2 別忽略CPU架構(gòu)aarch64和x86_64不通用確認包管理體系之后還要確認CPU架構(gòu)uname -mx86_64是Intel/AMD架構(gòu)aarch64是ARM架構(gòu)Kylin服務(wù)器上常見的飛騰、鯤鵬都屬于后者。離線rpm/deb包必須和架構(gòu)嚴(yán)格匹配否則安裝時直接報“架構(gòu)錯誤”。很多人踩過這個坑在有網(wǎng)機器上隨手下了x86_64的包拷到aarch64的機器上一裝就廢白白浪費一次傳輸時間。1.3 為什么不能照搬在線教程在線教程普遍這么寫yum install -y gcc-c或者apt-get install -y g。它之所以能一條命令搞定是因為系統(tǒng)里配置了可用的軟件源包管理器自動完成依賴解析。離線環(huán)境沒有可用源yum會立刻報“Could not resolve host”之類的錯誤。換句話說離線配置g真正要解決的不是“安裝”這個動作本身而是把在線時由包管理器自動完成的依賴解析和順序控制變成手工可控的流程。理解這一點后面看到缺依賴的報錯就不會慌。2. 離線安裝包從哪來先用好手邊的系統(tǒng)ISO再做依賴收集2.1 最省心的方案掛載Kylin安裝ISO當(dāng)臨時源我在隔離環(huán)境配基礎(chǔ)環(huán)境第一選擇永遠是找系統(tǒng)安裝鏡像。初始系統(tǒng)的機器一般會隨機器附帶同版本ISO直接掛載進系統(tǒng)看有沒有軟件倉庫目錄mkdir -p /mnt/kylin_iso mount -o loop /path/to/kylin.iso /mnt/kylin_iso ls /mnt/kylin_isoRPM系的光盤里通常有 repodata 目錄和 Packages 目錄。只要能看到 repodata說明ISO本身就是一套完整的離線yum源。順手檢查一下有沒有g(shù)相關(guān)包ls /mnt/kylin_iso/Packages | grep -E gcc|g\\如果有我強烈建議直接用它建本地源而不是手動rpm裝。因為ISO里的包跟系統(tǒng)版本配套依賴版本一致性最好幾乎不會出現(xiàn)編譯時鏈接庫版本不匹配的問題。Debian系的光盤結(jié)構(gòu)是 pool/ 和 dists/同樣能當(dāng)apt源用具體寫法在第3章講。2.2 有網(wǎng)同版本機器上收集依賴RPM系如果沒有ISO那就找一臺同版本、同架構(gòu)且能連網(wǎng)的非生產(chǎn)機器在那邊把依賴全部下載下來再打包拷過去。RPM系比較標(biāo)準(zhǔn)第一步安裝yum-utilsyum install -y yum-utils然后帶著依賴解析一起下載yumdownloader --resolve gcc-c --destdir/tmp/kylin_gcc_rpms--resolve參數(shù)非常關(guān)鍵它會連帶下載gcc、cpp、glibc-devel、libstdc-devel這些間接依賴。下載完直接打包cd /tmp tar czf gcc_rpms.tar.gz kylin_gcc_rpms拷到目標(biāo)機后解壓安裝。注意目標(biāo)機和下載機最好是同一個大版本比如都是Kylin V10 SP2。小版本差異偶爾會導(dǎo)致glibc或libstdc的符號版本對不上裝完能編譯但運行時可能報找不到GLIBCXX版本類錯誤。2.3 有網(wǎng)同版本機器上收集依賴Debian系Debian系同樣有對應(yīng)思路。在有網(wǎng)的同版本Kylin桌面機器上執(zhí)行apt-get install -y --download-only g--download-only會讓apt把g及其依賴的deb全部下載到 /var/cache/apt/archives/ 目錄。然后ls /var/cache/apt/archives/*.deb mkdir -p /tmp/kylin_gcc_debs cp /var/cache/apt/archives/*.deb /tmp/kylin_gcc_debs/ tar czf gcc_debs.tar.gz /tmp/kylin_gcc_debs拷到目標(biāo)機后用dpkg -i *.deb安裝。如果提示缺依賴再單獨補對應(yīng)的deb。也可以用 apt-rdepends 列出完整依賴樹但對于g這種基礎(chǔ)包--download-only通常已經(jīng)夠用。2.4 gcc-c的完整依賴鏈認識一下這幾個“老演員”為了后面報錯時能看懂先把核心依賴包的職責(zé)列出來包名體系作用gcc-c / gRPM / DEBC編譯器前端提供g命令gcc兩者都有C編譯器g工作時調(diào)用其內(nèi)部組件cpp兩者都有C/C預(yù)處理器負責(zé)頭文件展開libstdc-devel / libstdc-6-devRPM / DEBC標(biāo)準(zhǔn)庫開發(fā)包提供iostream頭文件和libstdc.so軟鏈glibc-devel / libc6-devRPM / DEB系統(tǒng)C庫開發(fā)文件提供stdio.h等基礎(chǔ)頭文件binutils兩者都有鏈接器ld、匯編器as編譯鏈接階段必須RPM系安裝順序一般照著依賴方向走cpp → glibc-devel → libstdc-devel → gcc → gcc-c。DEB系因為dpkg不強制嚴(yán)格順序?qū)嶋H操作常是一把dpkg -i *.deb下去缺什么再補什么。把這些包名記住后面報錯基本一眼就能定位缺的是誰。3. 核心實操Debian系與RPM系兩條安裝路徑3.1 RPM系手工裝按依賴順序 rpm -ivh如果依賴包已經(jīng)齊了可以手工安裝順序很重要cd /tmp/kylin_gcc_rpms rpm -ivh cpp-*.rpm glibc-devel-*.rpm libstdc-devel-*.rpm gcc-*.rpm gcc-c-*.rpm這里盡量不要一上來就rpm -ivh *.rpm --nodeps。--nodeps相當(dāng)于關(guān)掉依賴檢查短時間看是裝上了但有的包在文件層面被強行安裝實際內(nèi)容不完整編譯時才會在ld鏈接階段炸出“cannot find -lstdc”之類的問題。手工按順序裝的好處是如果缺了哪個包rpm會明確告訴你“xxx is needed by gcc-c”把它補進同一句命令再跑即可。安裝完成后驗證核心包是否都在rpm -qa | grep -E ^(gcc|g\\) rpm -qa | grep -E ^(libstdc\\-devel|glibc-devel)3.2 RPM系省事法createrepo 建本地倉庫再 yum install手工rpm裝適合一次性操作但如果你后面還要裝make、cmake、openssl-devel等一堆編譯依賴我強烈建議直接把離線包做成一個本地yum倉庫。先在目標(biāo)機上裝createrepoyum install -y createrepo如果這臺機器完全離線連createrepo都沒有可以到ISO里找或者在有網(wǎng)機器上把它和依賴一起下載過來。把離線rpm統(tǒng)一放到一個目錄例如mkdir -p /opt/kylin_local_repo cp /tmp/kylin_gcc_rpms/*.rpm /opt/kylin_local_repo/生成倉庫元數(shù)據(jù)createrepo /opt/kylin_local_repo然后新建 /etc/yum.repos.d/kylin-local.repo[kylin-local] nameKylin Local Repo baseurlfile:///opt/kylin_local_repo enabled1 gpgcheck0刷新緩存yum clean all yum makecache yum install -y gcc-c此時yum走的就是本地倉庫依賴自動解析跟在線環(huán)境一樣省心。后續(xù)再往這個目錄塞新的rpm包重新跑一遍createrepo --update /opt/kylin_local_repo就能繼續(xù)使用算是一勞永逸。3.3 Debian系安裝dpkg -i 和本地apt源Debian系的目標(biāo)機器上把拷貝過來的deb包全部放進一個目錄mkdir -p /tmp/kylin_gcc_debs tar xzf gcc_debs.tar.gz -C /tmp cd /tmp/kylin_gcc_debs dpkg -i *.deb如果dpkg提示有依賴未滿足一般有兩種情況一是部分deb沒有下載到二是安裝順序造成的“循環(huán)依賴”。前者回到有網(wǎng)機器上補下載后者可以跑dpkg --configure -a或者調(diào)整順序把libstdc6-dev、libc6-dev這類基礎(chǔ)包先裝再裝g。DEB系雖然不如RPM系對順序敏感但基礎(chǔ)包裝在前確實更穩(wěn)。如果你手里有桌面版的ISO也可以直接用file源。先看目標(biāo)系統(tǒng)的VERSION_CODENAMEgrep VERSION_CODENAME /etc/os-release然后把ISO路徑加入apt源echo deb [trustedyes] file:/mnt/kylin_iso codename main universe /etc/apt/sources.list apt-get update apt-get install -y gtrustedyes是讓apt信任本地非簽名源的必要項不加的話update會拒絕使用該源。4. 裝完別急著寫代碼驗證、配PATH、處理三個高頻報錯4.1 第一個C程序把工具鏈真正跑起來裝完之后先確認編譯器版本g --version正常會輸出類似 g (Kylin 10) 8.3.1 的信息。然后寫個最小程序驗證整套流程cat hello.cpp EOF #include iostream int main() { std::cout Hello Kylin std::endl; return 0; } EOF g hello.cpp -o hello ./hello輸出 Hello Kylin說明編譯器、頭文件、標(biāo)準(zhǔn)庫、鏈接器全部正常。這一步不能省因為有些機器g命令能啟動但一編譯就報錯下面這三個坑就是這種“半成功狀態(tài)”的典型。4.2 報錯一fatal error: iostream: No such file or directory這個報錯的意思是g可執(zhí)行文件找到了但找不到C標(biāo)準(zhǔn)庫頭文件。iostream頭文件在RPM系的libstdc-devel包、DEB系的libstdc-6-dev包里提供。排查方法ls /usr/include/c/ | head find /usr/include -name iostream如果目錄里沒有iostream文件說明開發(fā)包沒裝完整?;氐诫x線包目錄找到libstdc-devel開頭的rpm或deb包重新安裝。還有一種少見情況包裝了但路徑不在默認搜索范圍內(nèi)可以臨時設(shè)置export CPLUS_INCLUDE_PATH/usr/include/c/版本號不過正常yum/dpkg安裝會自動把路徑放對配置環(huán)境變量的方案只是兜底。4.3 報錯二/usr/bin/ld: cannot find -lstdc編譯過了預(yù)處理和編譯前端但在鏈接階段掛了提示找不到-lstdc。這里-lstdc對應(yīng)的是libstdc.so這個鏈接器輸入文件。系統(tǒng)運行時只有l(wèi)ibstdc.so.6動態(tài)庫本體開發(fā)包會額外提供一個不帶版本號的軟鏈讓鏈接器找到它ls -l /usr/lib64/libstdc.so*正常情況應(yīng)該看到/usr/lib64/libstdc.so - libstdc.so.6 /usr/lib64/libstdc.so.6 - libstdc.so.6.0.24如果少了第一條軟鏈就是缺libstdc-devel / libstdc-6-dev補裝后一般自動生成。這個報錯的本質(zhì)是開發(fā)包和運行包分離導(dǎo)致的理解了這一點以后遇到-lxxx找不到就都知道往對應(yīng)的-devel包上想。4.4 報錯三IDE報 cannot run compiler gQt Creator經(jīng)典問題這個報錯在熱搜里經(jīng)常出現(xiàn)很多人在Qt Creator或VS Code里配置工具鏈時看到。報錯關(guān)鍵詞是“cannot run compiler g”或者“could not find a valid executable”。在Kylin上遇到先不要懷疑編譯器壞了先查兩件事第一系統(tǒng)是否真的裝了g第二IDE里填的編譯器路徑對不對。終端里先跑which g正常會輸出/usr/bin/g。然后在Qt Creator中依次打開工具 → 選項 → Kits → 編譯器 → 添加 → GCC → CCompiler path填/usr/bin/gABI選系統(tǒng)對應(yīng)平臺。特別注意如果機器是aarch64別把交叉編譯的aarch64-linux-gnu-g當(dāng)本機編譯器填進去Kylin桌面自帶的Qt套件有時會自動識別出交叉編譯鏈導(dǎo)致編譯時找不到系統(tǒng)庫。路徑確認無誤后回到Kits頁面把編譯器和Qt版本綁到同一套Kit里。改完后先編譯一個空項目驗證不要直接在業(yè)務(wù)工程里來回試探。4.5 順手把PATH和軟鏈理一遍如果which g沒有輸出說明g的安裝位置不在PATH里。用下面命令定位find / -name g -type f 2/dev/null找到后加軟鏈或加PATH。最常用的是軟鏈到/usr/bin下ln -s /usr/bin/g-8 /usr/bin/g如果走的是源碼編譯GCC新版本g可能在/usr/local/bin/g而系統(tǒng)默認PATH里/usr/bin排在/usr/local/bin前面可能出現(xiàn)系統(tǒng)自帶的舊g搶先被調(diào)用的情況。這種問題在純rpm安裝方式下遇不到但離線場景下確實有人直接源碼編譯GCC所以順帶提一下。需要時把/usr/local/bin提到PATH前面即可。5. 把離線環(huán)境做成可復(fù)用工具包本地源與依賴清單存檔5.1 從零建一個可離線復(fù)用的本地yum源g裝完之后基礎(chǔ)環(huán)境并沒有結(jié)束后續(xù)大概率還要裝make、cmake、boost、openssl-devel等。與其每次離線都現(xiàn)找包不如定義一套固定目錄和配置文件。第3章建的/opt/kylin_local_repo就是現(xiàn)成基礎(chǔ)我通常的做法是把該機器需要的所有離線rpm按類別分目錄如compiler/、libs/、tools/每個目錄生成獨立repodata或者統(tǒng)一放一個大目錄只建一個repodata將整個目錄在部門內(nèi)網(wǎng)共享NFS或HTTP都行其它機器直接配同一個baseurl。共享的repo文件可以這樣寫[kylin-local] nameKylin Local Repo baseurlfile:///opt/kylin_local_repo # 如果通過NFS掛載直接用掛載后的本地路徑 # 如果通過HTTP分發(fā)則改成 baseurlhttp://內(nèi)網(wǎng)服務(wù)器ip/kylin_local_repo enabled1 gpgcheck0第二臺、第三臺機器就都是yum install -y gcc-c一條命令的事跟在線環(huán)境幾乎一樣。這才是離線配置的最終形態(tài)不是把某一次安裝做完而是把離線軟件源搭起來。5.2 Debian系的離線倉庫dpkg-scanpackages 生成索引Debian系對應(yīng)做法也簡單。把離線deb放到統(tǒng)一目錄例如/opt/kylin_debs然后安裝dpkg-devapt-get install -y dpkg-dev cd /opt/kylin_debs dpkg-scanpackages . /dev/null | gzip Packages.gz之后在/etc/apt/sources.list里加deb [trustedyes] file:/opt/kylin_debs ./apt-get update后就能install目錄里的deb。這個方案對維護離線Kylin桌面環(huán)境很順手更新依賴時往里丟新deb再重新掃描即可。5.3 記錄依賴清單讓下一臺機器2分鐘配完最后分享一個低成本高收益的習(xí)慣在配置完成的機器上把關(guān)鍵軟件包清單導(dǎo)出存檔。RPM系rpm -qa | grep -E ^(gcc|g\\|libstdc\\|glibc-devel|binutils|cpp) /root/kylin_compiler_deps.txtDEB系dpkg -l | grep -E gcc|g\\|libstdc\\|libc6-dev|binutils /root/kylin_compiler_deps.txt這份清單配合/opt/kylin_local_repo目錄里的具體rpm/deb文件就是完整的“環(huán)境快照”。下次再來一臺初始系統(tǒng)對著清單核對、下載、安裝基本不會漏東西。我實際配置多臺同型號機器時從掛載ISO到g跑通hello.cpp單臺耗時能控制在10分鐘以內(nèi)關(guān)鍵就在于把源和清單都固化了。最后再提一句我踩過的坑最開始圖省事在離線機上直接rpm -ivh *.rpm --nodeps一把梭表面全裝上了結(jié)果編譯Qt程序時鏈接階段逐個報缺庫補包補了整整三天。后來老老實實搭本地源、按依賴裝反而一次到位。離線配置g這件事真正的難度從來不是“裝上”而是“裝對”。把依賴鏈搞清楚、把本地源建好剩下就是機械操作了。