有些事情我們不知道該怎么辦, 但其實(shí)我們根本不知道自己在做什么
rpm 是什么?
rpm 是一種"包"的格式. 其中大致包含兩類數(shù)據(jù):
-
元數(shù)據(jù): 主要是 tag, 例如:
- Name: 軟件包的名稱戳玫,后面可使用%{name}的方式引用
- Summary: 軟件包的內(nèi)容概要
- Version: 軟件的實(shí)際版本號(hào)悠咱,例如:1.0.1等,后面可使用%{version}引用
- Release: 發(fā)布序列號(hào)童番,例如:1linuxing等昭伸,標(biāo)明第幾次打包黑忱,后面可使用%{release}引用
- Group: 軟件分組全庸,建議使用標(biāo)準(zhǔn)分組
- License: 軟件授權(quán)方式使兔,通常就是GPL
- Source: 源代碼包,可以帶多個(gè)用Source1谎势、Source2等源拄氯,后面也可以用%{source1}、%{source2}引用
- BuildRoot: 這個(gè)是安裝或編譯時(shí)使用的“虛擬目錄”
元數(shù)據(jù), 一部分是給人看的, 讓他們了解將要安裝的包都包含什么. 還有一部分是給包管理系統(tǒng)(yum)看的, 例如: 包的依賴關(guān)系.
-
文件數(shù)據(jù)
包含最終安裝都系統(tǒng)上的文件, 以及文件的屬性, 屬主等信息.
我們將軟件打成 rpm 的目的, 是要在系統(tǒng)上安裝該軟件. 所以, 我們應(yīng)該在 rpm 包里放什么呢? 這取決于你想在系統(tǒng)上安裝什么? 這完全由打包者決定. 通常一個(gè)軟件會(huì)包含: 可執(zhí)行文件, 配置文件, 文檔等. 但是, 如果你只想打包一些 html 頁面呢?. 也 ok 啊.
我們見過不少包管理系統(tǒng), 以及包的格式, 例如: yum & rpm, apt & deb, rubygem & gem, python pip & pip 等等. 不同的包管理系統(tǒng)和包的格式并沒什么本質(zhì)區(qū)別.
編譯?
我們知道要將源碼放到 SOURCES 目錄, 文件名可能是 abc-1.1.1.tar.gz, 但是 rpmbuild 是怎么把源碼最終變成 rpm 包的呢?
-
將源碼文件解壓到 BUILD 目錄, 目錄可能是叫 abc-1.1.1. 通常源碼包解壓出來的目錄名稱和源碼包的名字是對(duì)應(yīng)的, 但是總有不一致的情況, 尤其是一些私有軟件, 打包源碼時(shí)往往不是很規(guī)范, 甚至連版本號(hào)都沒有. %setup 可以用來指定將源碼解壓到什么目錄:
- %setup 不加任何選項(xiàng)它浅,僅將軟件包打開。
- %setup -n newdir 將軟件包解壓在newdir目錄镣煮。
- %setup -c 解壓縮之前先產(chǎn)生目錄姐霍。
這里列的只是一部分參數(shù), 這些參數(shù)其實(shí)不重要, 因?yàn)槟阍谑謨陨隙寄懿榈?
后面的步驟都會(huì)在解壓出來的源碼目錄進(jìn)行.
后面的步驟都會(huì)在解壓出來的源碼目錄進(jìn)行.
后面的步驟都會(huì)在解壓出來的源碼目錄進(jìn)行.
-
在解壓出來的源碼目錄進(jìn)行編譯.
當(dāng)然, 有些軟件不需要編譯, 或者你已經(jīng)編譯好了(你完全可以把編譯好的程序打成 tag.gz 丟到 SOURCES 目錄, spec 中就不需要定義編譯相關(guān)的內(nèi)容了. 就跟打包一堆 html 沒什么區(qū)別).
%build 定義了如何編譯你的軟件, make 也好, maven 也好, 如果不需要編譯, 那就空著就好了. 項(xiàng)目原本怎么編譯, 把相應(yīng)的命令貼到 %build 就好了, 并沒有什么區(qū)別. 如果打包失敗是因?yàn)榫幾g不通過, 那對(duì)不起, 這個(gè)鍋 rpmbuild 不會(huì)背.
編譯的環(huán)境就是系統(tǒng)環(huán)境, 不存在一個(gè)隔離的"編譯環(huán)境", 所以, 如果缺 lib, 缺頭文件, 在系統(tǒng)上安裝就好了.
rpmbuild 只是替你"敲"了那些編譯命令而已, 和你自己敲沒什么區(qū)別.
-
"安裝"
編譯過 c/c++ 項(xiàng)目的同學(xué)知道, 編譯(make) 完成后, 通常需要安裝(make install). 將編譯的結(jié)果部署到系統(tǒng)的某個(gè)或者某幾個(gè)目錄.
rpm 打包過程也包含安裝(%install)這一步, 但并不是"真"的安裝到系統(tǒng)的某個(gè)目錄. 而是安裝到以 %{RPM_BUILD_ROOT} 為根的路徑下.
例如, 你有一個(gè)文件 abc, 希望最終部署到系統(tǒng)的 /usr/local/bin/ 下, 那么 %install 階段, 我們應(yīng)該把它安裝到 %{RPM_BUILD_ROOT}/usr/local/bin/ 下. 也就是以 %{RPM_BUILD_ROOT} 為根的絕對(duì)路徑.
為什么要這么干呢? 目的是為了構(gòu)建 rpm 包內(nèi)的目錄結(jié)構(gòu), 方便后續(xù)的打包工作.
-
打包
把元數(shù)據(jù) 和 %{RPM_BUILD_ROOT} 按照一定的格式打包在一起就是最終的 rpm 包了. 會(huì)存放在 RPMS 目錄下.
有了按照系統(tǒng)路徑構(gòu)建的 %{RPM_BUILD_ROOT}, 打包或者安裝階段就不用關(guān)心一個(gè)文件在最終 rpm包 安裝的時(shí)候應(yīng)該放在什么路徑了-- 包里在什么路徑, 就安裝到什么路徑.
-
安裝
將 rpm 包拷貝到目標(biāo)機(jī)器, 或者加入到目標(biāo)機(jī)器可以訪問到的本地 yum 倉庫后. 就可以在目標(biāo)機(jī)器上安裝了.
rpm 會(huì)將包里的文件按照其路徑, 放到系統(tǒng)的對(duì)應(yīng)位置. 感覺上就好像你在根目錄解壓一個(gè) zip 包一樣. 包里的文件"自動(dòng)"找到了自己的位置.
yum 除了拷貝文件外, 還會(huì)檢查元數(shù)據(jù)里定義的依賴, 以便將依賴項(xiàng)也一起安裝. 解決包依賴, 也是 yum 最主要的任務(wù).
總結(jié)
所以, 回頭看看, 什么是 rpm 呢? rpm包和一個(gè)附加了一點(diǎn)元數(shù)據(jù)的 zip包有什么區(qū)別呢?
rpm 如何構(gòu)建呢? 我們通過 spec 在一個(gè)臨時(shí)目錄(%{RPM_BUILD_ROOT})構(gòu)建了一個(gè)目錄樹, 同時(shí)聲明了一些元數(shù)據(jù), 然后 rpmbuild 把目錄樹和元數(shù)據(jù)打成一個(gè)包, 就成了 rpm.
spec 中那些宏總是讓我們很費(fèi)解, 但是考慮到 rpm包 被發(fā)明的時(shí)間, 你如果有一點(diǎn) C/C++ 的背景理解起來可能會(huì)容易一些, rpm 已經(jīng)是一個(gè)比很多工程師年齡都大的"長輩"了.