為什么要打包?
制作 rpm 不僅僅是打包,更可以解決菜單創(chuàng)建、打補釘、完成大量預配置、與其他軟件包互動等操作。使用源代碼安裝要求用戶了解基本的編譯過程、能夠應付各種不能編譯的意外、必須自己完成抽象的配置、甚至懂得軟件開發(fā),能夠自己打補釘,……對非計算機專業(yè)的用戶而言簡直就是天方夜譚。這是把軟件開發(fā)的最后一步拋給了用戶,作為發(fā)行版,這是極不負責任的!也是不現(xiàn)實的,除非用 lfs,但那是一本菜譜,不是真正的發(fā)行版。 軟件作者發(fā)布源代碼是正確的,負責的作者一般都同時提供 rpm 和 deb 包以及它們的源代碼包。除非他們不會制作。愿意使用什么,那是個人的自由,但對外就不能只想到自己。GNU 精神是一種公益精神,沒有奉獻精神,在自由軟件領域是要遭唾棄的! 直接使用其他發(fā)行版的 rpm 常常是不行的。不知道大家看沒看“惱人的依賴關系”這個帖子。可以在技術支持區(qū)搜索一下。任何兩個發(fā)行版本在二進制上都是不能兼容的!他們實際是不同的操作系統(tǒng)。不僅使用的庫文件不同,配置也迥異。特別是同一個發(fā)行版的不同版本更不兼容。任何包都必須在本地重新編譯,而且不一定通得過,因為還有 spec 宏的兼容問題!如果要在別的發(fā)行版上使用,必須用源碼編譯,這是常識??紤]文件布局和配置問題,有時直接編譯也是不夠的,必須修改 spec,甚至自己打補丁。 如何創(chuàng)建 rpm 包? rpm 建包原理其實不復雜。寫 spec 相當于一種腳本編程,主要是在 spec 里提供一些軟件相關信息,以及安裝、卸載前后要執(zhí)行的腳本,然后展開壓縮的源代碼包,打上補丁,執(zhí)行編譯,然后利用 make install 可以重新指定安裝目的地的特性,把編譯好的文件安裝到指定的虛擬根目錄下的指定位置里,一般是虛擬的 /usr 里,然后把這些目錄、信息和腳本打成一個壓縮包,即 rpm 包。同時可選地生成源碼包 src.rpm。當然有很多具體細節(jié)問題。您應該首先閱讀軟件的 readme 和 INSTALL 文件。 打包原則 1. 任何人都應該在系統(tǒng)現(xiàn)有 src.rpm 的 spec 基礎上修改更新,除非沒有這樣的包。這可以省去很多麻煩,少走彎路。 2. 任何人都無權刪除別人的 changelog 和原始打包者的信息,這是對別人的不尊重。但你可以追加自己的信息。 3. 盡可能在 spec 里使用系統(tǒng)的標準宏定義,而不要用非標準寫法。 4. 任何人都不應該直接提供修改后的源代碼,而應該以補丁形式發(fā)布你的修改,在 spec 里完成打補丁操作。務必做到一個補丁只解決一個問題,這樣才能確保補丁的可重用性,否則版本升級后補丁很容易失效。如果你確信自己的補丁是清潔補丁,盡可能發(fā)給上游開發(fā)者,這樣才能一勞永逸。你所打的任何補丁,其授權方式必須和被修改源代碼保持一致。 5. rpm 不是跨平臺打包技術。確保軟件的二進制代碼能夠跨平臺運行,不是系統(tǒng)軟件打包者要考慮的事,而是應用軟件作者和獨立二進制代碼發(fā)布者應該考慮的事。我們沒有責任和義務確保從我們系統(tǒng)里拆解下來的部件能夠運行于其他系統(tǒng)上,不支持,更不提倡這種移花接木的作法。 試圖解決跨平臺問題的打包技術,我印象中有 autopackage 和 klik 技術,參見: http:// http://klik. 預備知識: 首先我們觀察一下 rpm 文件名的特點。一個 rpm 包文件名通常由 5 段組成: %{name}-%{version}-%{release}.ix86.rpm cutedict-1.1-1mgc.i686.rpm 這里 %{name}=cutedict,%{version}=1.1,%{release}=1mgc,ix86=i686,如果是為 athlon 芯片家族編譯的包,這里就是 athlon,依此類推。 注意: 下面是一個spec 模板。 1. 凡是行首加上 # 的都被注釋掉了,實際運行時不起作用,如要使其生效,請去掉注釋符 #。 2. 凡是以 %{***} 和 %*** 形式出現(xiàn)的符號都是“宏”,很多宏都是系統(tǒng)預定義的[注2],也可以是自己定義的。 3. 下面的黑體字是 spec 文件的關鍵字,不能寫錯。 4. 有不明白的地方可以參見跟帖里的參考文獻。 5. 如果軟件沒有使用 GNU autotool 創(chuàng)建,而是自己寫的 Makefile,這就導致不能按照常規(guī)方法打包,非常麻煩。 6. 服務器軟件通常都需要大量預配置工作,spec 打包絕非一兩天能解決,需要深入研究很多東西和反復實踐,建議初學者不要嘗試。 7. 其他發(fā)行版的 spec 與 src.rpm 是很好的教材,建議打包前先找找 Fedora 或 SuSE 的文件學習,能借鑒最好,但不應該不修改照搬過來或使用 Mandrake/Mandriva 的文件,因為它使用的大量專有宏定義和我們不兼容,甚至 src.rpm 直接編譯都通不過。 ------------------------------------------------------------------ [spec 文件頭部] # Initial spec file created by autospec #這里是一些注釋 %define _noautoreq perl(Plot) perl(WidgetDemo) #這里用 %define 自定義一個系統(tǒng)里沒有的叫做 _noautoreq 的宏,后面可以用 %{_noautoreq} 引用。 Name: software #這是軟件包名稱,后面可以用 %{name} 引用 Summary: a software #這是軟件包的內容提要 #Summary(zh_CN): #這里寫入中文內容提要(如果有必要。不建議使用,因為如果系統(tǒng)里的默認編碼與此處不符,會導致顯示亂碼。例如:我們使用 GBK,如果這里的中文是 UTF-8 編碼,在 kpackage 里就會顯示亂碼,但是 synaptic 可能能夠正確顯示,但需要把 zh_CN 改為 zh_CN.UTF-8 ) Version: number #這是軟件的實際版本號,例如 2.1.6、2.2final 等,后面可以用 %{version} 引用 Release: number #發(fā)布序列號,我們用 1mgc、2mgc 等等,標明這是第幾次打包。如果軟件本身是預覽版,比如 pre6 版,則寫成 pre6_1mgc、pre6_2mgc,后面可以用 %{release} 引用 Group: Applications/Multimedia #這是軟件分組,建議使用標準分組,參見下面:[注1] #Group(zh_CN): #中文軟件分組(如果有必要) License: GPL #這是軟件授權方式,通常是 GPL Source: %{name}-%{version}.tar.gz #這是源代碼(通常是壓縮包),可以帶有完整的網址,可以用正整數(shù)標識多個源 Source0 Source4 Source5 Source100,數(shù)字不必連續(xù)排列,后面可以用 %{SOURCE0}、%{SOURCE4}、%{SOURCE5}、%{SOURCE100} 引用。例如 http://www./src/%{name}-%{version}.tar.gz BuildRoot: %{_tmppath}/%{name}-%{version}-%{release}-buildroot #這是 make install 時使用的“虛擬根目錄”也稱為“構建根目錄”,通常是 /var/tmp/軟件名稱-版本號-發(fā)布序列號-buildroot。對于服務器環(huán)境,可能同時有多人操作,為了確保編譯軟件時臨時目錄不會相互覆蓋,還需要加上當前用戶的標識:BuildRoot: %{_tmppath}/%{name}-%{version}-%{release}-buildroot-%(%{__id_u} -n) make install 時一般會將軟件安裝在 /var/tmp/軟件名稱-版本號-發(fā)布序列號-buildroot/usr/ 下的 bin/ 下(可執(zhí)行文件)、share/ 下(數(shù)據(jù)、資源文件)、lib/ 下(動態(tài)共享庫文件,即 .so 文件 <Share Object>,相當于 windows 下的 DLL 文件)等等,例如 /var/tmp/cce-0.51-1mgc-buildroot/usr/bin/cce。不過實際不一定都是這樣,具體情況具體對待 # 下面是可選的字段 URL: http://www./ #這是軟件主頁地址 #Vendor: Red Hat Co.,ltd. #這是發(fā)行商或者打包組織的信息,我們統(tǒng)一寫成 MGC Group,不過這一行可以省略,把它寫入 /usr/lib/rpm/macros 標準宏定義文件里,該文件的 Vendor 這行定義是空的,而且通常前面用 # 注釋掉了 #Distribution: Red Hat Linux #這是軟件針對的發(fā)行版標識,我們是 Magic Linux Patch: src-%{version}.patch #這是補丁源代碼(可以是壓縮包),可以用正整數(shù)標識多個源 Patch1 Patch4 Patch6,數(shù)字不必連續(xù)排列。 Prefix: %{_prefix} #指定 make install 時在虛擬根目錄里的安裝位置,通常用標準的 %{_prefix} 宏,它代表 /usr。這里指定后,用戶可以在 rpm 安裝階段重新指定安裝到其他位置,如 /opt,否則就不能改變安裝位置。 Prefix: %{_sysconfdir} #如果軟件有些文件并非都安裝到 %{_prefix},那么你需要指明其他位置。例如你需要把一個配置文件放到 /etc 下面,這顯然不在 /usr 下面,此時你需要前方這種寫法。%{_sysconfdir} 宏代表 /etc。這里指定后,用戶可以在 rpm 安裝階段重新指定這些文件安裝到其他位置,如 /opt/etc,否則就不能改變安裝位置。[注3] #BuildArch: noarch #編譯目標處理器架構,就是今后軟件運行時的 CPU 類型。noarch 是不指定架構,通常標準默認是 i386,定義在了系統(tǒng)的標準宏定義文件 /usr/lib/rpm/macros 里 [注2]。實際編譯時可以在 rpmbuild 命令行用 --target=i686 參數(shù),spec 里通常不寫這行。 #Requires: libpng-devel >= 1.0.20 zlib libpng #這里羅列所有安裝本包時需要先行安裝的包(依賴包),通常軟件會依賴這些包里的一部分文件??梢苑殖啥嘈衼韺憽H绻@里不寫明依賴包,打包時系統(tǒng)僅僅會自動把具體依賴的 .so 文件寫進 rpm 包,而不會注明這些文件屬于哪些軟件包,這會對用戶造成困惑,因為他們很難知道這些文件屬于哪些軟件包。注意:如果使用 >= 這樣的符號,務必在其兩邊各保留一個空格 #Obsoletes: #這里列出的軟件包都是“陳舊”的,當升級安裝本包的時候,這里列出的包都會被自動卸載! NoAutoReq: %{_noautoreq} #這里的意思是禁止自動查找對 spec 文件頭部預定義的 _noautoreq 宏里定義的兩個軟件包[perl(Plot) 和 perl(WidgetDemo)]的依賴關系,通常對于 prel 模塊需要這樣處理。因為即便你在 Requires 字段指明了本包所依賴的包含這兩個模塊的那些軟件包,安裝 本包的時候系統(tǒng)仍然會直接查找是否安裝有這些 perl 模塊,而不會查找那些包含這兩個模塊的軟件包是否已經安裝。 #PreReq: loop #如果在 %pre 字段執(zhí)行的腳本需要使用一些特殊命令,例如 loop,你需要在此標明 #Requires(post): loop #這是上面一行的另一種寫法,依此類推,還有其他幾個類似的關鍵字: #Requires(pre) #Requires(preun) #Requires(postun) #Autoreq: 0 #這里使用 0 關閉了自動標注本軟件包需要的依賴關系的功能,使用 1 或者不寫此行(默認)就是開啟自動標注依賴關系的功能。自動依賴校驗只會通過 pkgconfig 找出依賴的 .so 文件,而絕對不是軟件包!可以通過命令反查生成的 rpm 包所依賴的這些 .so 文件屬于哪個包,再把這些依賴的包的名稱寫進 spec,最后重新編譯就行了。 #Autoprov: 0 #這里使用 0 關閉了自動標注本軟件包提供的依賴關系的功能,使用 1 或者不寫此行(默認)就是開啟自動標注依賴關系的功能 #Autoreqprov: 0 此關鍵字兼具上述兩條的功能 #BuildRequires: libpng-devel >= 1.0.20 #這是編譯時依賴的包 #Provides: lda #這里標注本軟件包提供的某些特定功能。例如 sendmail 在沒有本地遞送代理 [local delivery agent (lda)] 時不能工作,而你的軟件包恰好提供了這一功能,你需要在此標明。而在 sendmail 的 spec 里你需要寫明:Requires: lda Packager: Tony Black <tony@> #這是打包者的信息 %description 軟件的詳細說明 This is the description... #%description -l zh_CN 中文軟件說明(如果有必要。不建議使用,因為如果系統(tǒng)里的默認編碼與此處不符,會導致顯示亂碼。例如:我們使用 GBK,如果這里的中文是 UTF-8 編碼,在 kpackage 里就會顯示亂碼,但是 synaptic 可能能夠正確顯示,但需要把 zh_CN 改為 zh_CN.UTF-8 ) [spec 文件體部] %prep #下面開始預處理 %setup -n %{name}-%{version} #到這里,系統(tǒng)把源碼包從 /usr/src/mBuild/SOURCES 解壓縮到 /usr/src/mBuild/BUILD/%{name}-%{version} ,并轉到那里展開的壓縮包目錄(%{name}-%{version} )里,以便完成打補丁等準備工作,最后還要退回到 /usr/src/mBuild/BUILD 目錄下。-n 后面指定的參數(shù)代表 tar 包展開后生成的目錄名,一般 -n %{name}-%{version} 是不需要的,除非 tar 包名稱和展開后生成的目錄名不符,或者你要處理多個 tar 包。如果打包時報告找不到 ./configure 說明 -n 參數(shù)指定的目錄不對,或者軟件源代碼目錄里沒有 configure 腳本 (比如你的代碼是從 cvs 里 commit out 出來的,你需要進行一些準備工作,比如通過運行 autogen.sh 腳本來自動創(chuàng)建 configure 腳本。這具體看是哪個軟件,不同軟件有不同的方法)。如果有多個源代碼包要編譯,用“-n 名稱”指定多個 setup 字段。 %patch #這里開始打補丁。例如 %patch0 -p1,%Patch2 -p1 -b .xxx.patch 這里 %patch0 是對第一個補丁的引用,%Patch2 -p1 -b .xxx.patch 表明第二個補丁是壓縮包,要先解壓縮,再打補丁。 -p1 是 patch 命令的常用參數(shù),代表忽略 patch 時的第一(頂)層目錄。(為什么?因為創(chuàng)建補丁時兩個比照的目錄或者文件名肯定是不同的。參見[注5]) %configure #系統(tǒng)重新進入 /usr/src/mBuild/BUILD/%{name}-%{version} 執(zhí)行 configure 腳本進行配置,然后返回 /usr/src/mBuild/BUILD 目錄下。%configure 是 rpm 定義的標準配置宏,含義很復雜,但絕對標準。具體含義參見 [注2]。非標準寫法: CFLAGS="$RPM_OPT_FLAGS" \ CXXFLAGS="$RPM_OPT_FLAGS" \ ./configure --prefix=%{_prefix} 或者: CFLAGS="$RPM_OPT_FLAGS" CXXFLAGS="$RPM_OPT_FLAGS" ./configure --prefix=%{_prefix} %build #開始構建包。系統(tǒng)重新進入 /usr/src/mBuild/BUILD/%{name}-%{version} 執(zhí)行 make,然后返回 /usr/src/mBuild/BUILD 目錄下。 make %{?_smp_mflags} OPTIMIZE="%{optflags}" #這是 make 命令,其兩個參數(shù)的含意是: %{?_smp_mflags} 如果系統(tǒng)里定義了make 的并行編譯參數(shù),則使用這個參數(shù)。例如: -j2 表示 make 同時執(zhí)行兩個文件的編譯操作。如果你使用多個 CPU 或者非單核 CPU,這個參數(shù)可以明顯提高編譯速度,但是這里指定的數(shù)字不宜超過你的 CPU 內核數(shù)量+1。 OPTIMIZE="%{optflags}" 如果系統(tǒng)里定義了 gcc 的優(yōu)化參數(shù),則在軟件默認優(yōu)化參數(shù)的基礎上追加使用這里指定的優(yōu)化參數(shù)。例如: -O2 -g -pipe 表示使用 gcc 第二優(yōu)化級、為調試工具 GDB 提供額外的支持信息、使用管道而不是臨時文件以便加快編譯速度。 這兩個參數(shù)具體定義在:/usr/lib/rpm/mBuild/macros 里。 %install #下面開始將編譯好的軟件安裝到虛擬的根目錄。系統(tǒng)重新進入 /usr/src/mBuild/BUILD/%{name}-%{version} 執(zhí)行 make install,然后返回 /usr/src/mBuild/BUILD 目錄下。 rm -rf $RPM_BUILD_ROOT #先清理安裝目的地——虛擬根目錄 %makeinstall #這是 rpm 定義的標準的安裝宏,含義很復雜,但絕對標準。具體含義參見 [注2]。 非標準寫法: make DESTDIR=$RPM_BUILD_ROOT install 或者 make prefix=$RPM_BUILD_ROOT install (這行原先寫錯了,非常抱歉) %clean #清掃戰(zhàn)場,打包完成后刪掉編譯過程產生的中間文件、目錄 [ "$RPM_BUILD_ROOT" != "/" ] && rm -rf "$RPM_BUILD_ROOT" #如果虛擬根目錄不是真正的 / 目錄,就刪除掉。這里將軟件打包時安裝到的虛擬根目錄刪掉。通常直接用 rm -rf $RPM_BUILD_ROOT 就很安全。 rm -rf $RPM_BUILD_DIR/%{name}-%{version} #將 /usr/src/mBuild/BUILD/軟件名稱-版本號 目錄刪掉。這里是編譯過程生成的中間文件。注意:這里的 %{name}-%{version} 必須和 %setup -n %{name}-%{version} 指定的相應內容保持一致。 按照我們在 /usr/lib/rpm/macros 里的定義,通常 %clean rm -rf $RPM_BUILD_ROOT rm -rf $RPM_BUILD_DIR/%{name}-%{version} 也可以寫成 %clean %{__rm} -rf %{buildroot} %{__rm} -rf %{_builddir}/%{name}-%{version} %pre #rpm 包安裝前執(zhí)行的腳本。 %post #rpm 包安裝后執(zhí)行的腳本。 /sbin/ldconfig #這里舉例,ldconfig 用于安裝庫文件后進行“注冊”,這么說不準確,但好理解。這里可以是任何 sh 腳本。 %preun #rpm 包卸載前執(zhí)行的腳本。 %postun #rpm 包卸載后執(zhí)行的腳本。 if [ "$1" = "0" ]; then /sbin/ldconfig fi 或者寫作: if [ $1 -eq 0 ]; then /sbin/ldconfig fi ★★★ 如果您的包作為系統(tǒng)包的一部分,需要通過發(fā)行版本的安裝程序安裝的話,不要指望能使用內嵌腳本執(zhí)行任何重要操作,包括創(chuàng)建任何文件。因為安裝程序的運行環(huán)境不可能完全等同于安裝后實際運行時的系統(tǒng)環(huán)境,某些操作是不能正確執(zhí)行的。一般,安裝程序在安裝后期會執(zhí)行一些補償操作,來完成諸如庫文件和內核模塊注冊、初始環(huán)境設置等操作,所以你不必擔心庫文件安裝不正確。 具體舉例來說:最常見的 %post 小節(jié)的腳本在系統(tǒng)初始化安裝階段就很可能得不到正確執(zhí)行。因為安裝程序所處的小 linux 系統(tǒng)環(huán)境不同于安裝后的真實系統(tǒng),而此時的真實系統(tǒng)還不完整,即便立即 chroot 切換入真實系統(tǒng)也未必能正確執(zhí)行,況且安裝一個 rpm 時其內嵌腳本不可能等你切換入真實系統(tǒng)才執(zhí)行。所以除了 ldconfig 之類的命令外,盡可能不要使用內嵌腳本,特別是不要創(chuàng)建任何文件,比如配置文件或者 desktop 文件,所有這些都必須靜態(tài)創(chuàng)建好。您可以在 install 字段完成這些創(chuàng)建工作,也可以事先創(chuàng)建好,并把它們作為 source 的一部分。 既然內嵌腳本在系統(tǒng)初始化安裝階段都是不可靠的,那么上文提到的 ldconfig 又有什么作用呢?原來,通常安裝程序都會在安裝包結束后,自動創(chuàng)建 /etc/ld.so.conf,并且執(zhí)行一次 ldconfig,從而完成對所有庫文件的注冊。如果這個包是在系統(tǒng)安裝后額外安裝的,那么所有的內嵌腳本都應該被這個真實的系統(tǒng)正確執(zhí)行,此時的 ldconfig 就會被正確執(zhí)行。 ★★★ 我們可以看到,在 postun 小節(jié)定義的腳本里多出來一個 if 判斷語句,這事干什么用的呢?這里的 $1 是什么意思呢?原來 rpm 相當強大,以其包升級操作為例,它會這樣執(zhí)行: 新包的 pre 腳本 安裝文件 新包的 post 腳本 舊包的 preun 腳本 刪除安裝過程沒有覆蓋的全部文件,但不包括重要配置文件 舊包的 postun 腳本 如果有“觸發(fā)”腳本,實際操作會更復雜。 通常在 postun 腳本里我們執(zhí)行的都是一些清掃垃圾的操作,比如刪除程序額外創(chuàng)建的臨時文件、配置文件(我們建議通過交互式方式執(zhí)行此操作,詢問用戶是否刪除程序運行時創(chuàng)建的配置文件,因為有些配置文件用戶未必想要刪除)。卸載軟件包沒問題,但是升級操作就可能造成災難性后果:剛剛安裝好的軟件包被刪掉了一部分文件。為了避免這樣的局面,rpm 提供了一種信號機制,不同操作會返回不同信號,并且把它存放到默認變量 $1 當中:0 代表卸載、1 代表安裝、2 代表升級。這樣我們就可以通過判斷 $1 的值來決定怎樣執(zhí)行腳本。上面的腳本就表示:僅當執(zhí)行卸載操作的時候才執(zhí)行 /sbin/ldconfig 命令。 ★★★ 在 rpm 內嵌腳本里的重要命令需要使用完整的或稱絕對路徑,例如 /sbin/ldconfig 等,這是為了確保正確的命令被執(zhí)行。由于用戶自己可能重新定義了 PATH 環(huán)境變量,導致其他位置上的 ldconfig 可執(zhí)行程序的搜索路徑先于 /sbin/ldconfig,可能產生難以預料的后果。 %files #本節(jié)定義哪些文件、目錄將被打進 rpm 包里。如果你認為哪些文件不必打進 rpm 包里(一般是 debug、src 和 devel 文件、目錄),你就不要列在這里,或者使用 %exclude 關鍵字指明哪些文件不打進 rpm 包里。你甚至可以在 spec 文件的其他字段安裝或者刪除一些特定的文件,這就是比較復雜的技術了。但是如何才能知道到底軟件向系統(tǒng)內安裝了哪些目錄和文件呢?這個問題有點復雜。參見[注4]。注意:此處系統(tǒng)的當前路徑指的就是虛擬的根目錄。所以虛擬的根目錄路徑(例如 /var/tmp/cce-0.51-1mgc-root/)不要寫在這里。應該直接用類似 %{_bindir} 的宏(表示 /usr/bin ) 來指定包含的目錄,也可以單獨指定一個或一組文件。 %defattr(-,root,root) 指定包裝文件的屬性,代表(mode, owner, group) 即文件屬性、文件屬主、用戶群組,- 代表屬性為默認值,對文本文件是八進制數(shù)0644,可執(zhí)行文件是 0755。下面指定具體哪些目錄或文件將被打進包里,很多宏的定義要看你的具體系統(tǒng)[注2] #下面具體指定打進 rpm 包的文件、目錄,例如: %dir %{_datadir}/tst/ %dir %{_datadir}/tst/plugin/ %{_bindir}/tst %{_datadir}/tst/plugin/libtest.so "/usr/share/tst/plugin/*.png" %{_datadir}/tst/plugin/test.plugin %config %{_datadir}/tst/tst.conf %exclude /usr/src #如果上面列出的目錄里包含一些你不想要的東西,比如源代碼(src),你可以在此將他們“摳”出去。這里指定具體哪些目錄或文件將被排除在包外,即不打進包,一般是 debug、src 和 devel 文件、目錄。 %files devel #這里分出 devel 包,主要包含與軟件開發(fā)相關的頭文件與庫文件包。 %defattr(-,root,root) %{_includedir} 代碼: 這是 %files 小節(jié)的最簡單寫法: %files %defattr(-,root,root) %{_sysconfdir} #如果您提供了位于 /etc 的設置文件,需要這行 %{_prefix} #將安裝目標目錄里的所有東西都打進 rpm 包,除了 %exclude 列出的內容 %exclude %{_prefix}/*/debug* #除掉所有的 debug 調試文件* %exclude %{_prefix}/src #除掉所有的源代碼文件* *注意:如果沒有這樣的文件、目錄,則打包過程會出錯,只要在 %exclude 前方加上 # 注釋掉這行就行了。 [spec 文件尾部] %changelog #下面是標準變更日志,日期一定不能寫錯,只能是英文格式。 * Sun Oct 31 2004 Tony Black <tony@> - modify the spec file and rebuild * Sun Oct 03 2004 Lover <root@Lover> - initial spec file created by autospec ver. 0.8 with rpm 3 compatibility ----------------------------------------------------------------------- 把源代碼壓縮包、補丁等等放到 /usr/src/mBuild/SOURCES 目錄里,把 spec 文件放到 /usr/src/mBuild/SPECS 目錄里,在 SPECS 目錄里以 root 身份執(zhí)行: rpmbuild -ba --target=i686 xxx.spec 即可在 /usr/src/mBuild/RPMS/i686 里生成 rpm 包,一般還會有 debug info 包,對普通用戶基本沒什么用。在 /usr/src/mBuild/SRPMS 里則生成 src.rpm 包。 如果只想生成二進制包,使用下面命令: rpmbuild -bb --target=i686 xxx.spec 如果只想生成源代碼包,使用下面命令: rpmbuild -bs --target=i686 xxx.spec 注1: rpm 軟件包系統(tǒng)標準分組在這里: /usr/share/doc/rpm-4.3.2/GROUPS 大致內容如下: Amusements/Games Applications/Archiving Applications/Communications Applications/Databases Applications/Editors Applications/Emulators Applications/Engineering Applications/File Applications/Graphics Applications/Internet Applications/Multimedia Applications/Productivity Applications/Publishing Applications/System Applications/Text Development/Debuggers Development/Languages Development/Libraries Development/System Development/Tools Documentation System Environment/Base System Environment/Daemons System Environment/Kernel System Environment/Libraries System Environment/Shells User Interface/Desktops User Interface/X User Interface/X Hardware Support 注2: 各種宏定義在系統(tǒng)這里: /usr/lib/rpm/macros 通常我們要對其適當優(yōu)化一下,修改如下: %vendor MGC Group %optflags -O2 -g -pipe %_arch i686 這里相當于 rpmbuild 的參數(shù) --target=i686 指將來運行軟件包時的環(huán)境 %_build_arch i686 這里相當于 rpmbuild 的參數(shù) --build=i686 指建包時的環(huán)境(你的機器),這可以比默認的 i386 快一些。 常見宏定義(左側是宏名,右側是相應的定義): %_prefix /usr %_exec_prefix %{_prefix} #展開后是 /usr %_bindir %{_exec_prefix}/bin #展開后是 /usr/bin %_sbindir %{_exec_prefix}/sbin #展開后是 /usr/sbin %_libexecdir %{_exec_prefix}/libexec #展開后是 /usr/libexec %_datadir %{_prefix}/share #展開后是 /usr/share %_sysconfdir %{_prefix}/etc #展開后是 /usr/etc 但是在 magic linux 里 %_sysconfdir 代表的是 /etc,這是由另一個被發(fā)行版特殊定制的文件決定的! %_sharedstatedir %{_prefix}/com #展開后是 /usr/com %_localstatedir %{_prefix}/var #展開后是 /usr/var %_libdir %{_exec_prefix}/lib #展開后是 /usr/lib %_includedir %{_prefix}/include #展開后是 /usr/include %_infodir %{_prefix}/info #展開后是 /usr/info %_mandir %{_prefix}/man #展開后是 /usr/man 在 magic linux 里 %_mandir 代表的是 /usr/share/man ***注意*** 僅當你使用標準配置宏 %configure 的時候,文件才會被指定到上述標準位置上。否則,如果你在 %file 字段使用這些標準宏就可能出錯,系統(tǒng)可能報告找不到這些文件,因為它們可能默認安裝到了別處。 ********* 已安裝的 RPM 包數(shù)據(jù)庫在這里: /var/lib/rpm/ 注3: 軟件包安裝時用參數(shù) --prefix=<dir> 重新指定安裝位置。例如: 軟件包默認安裝到 /usr 下,你希望安裝到 /opt/usr 下,則使用命令: rpm -ivh --prefix=/opt/usr xxx.rpm 如果你還有一些文件默認安裝到 /etc 下,你需要安裝到 /usr/etc 下,則要改用參數(shù) --relocate=<old>=<new>,例如: rpm xxx.rpm --relocate=/usr=/opt/usr --relocate=/etc=/usr/etc 如何知道 rpm 軟件包到底向系統(tǒng)什么位置安裝了什么文件呢?,你可以使用下面的命令查詢: rpm -qpl xxx.rpm 注4: 任何沒有被列在 %files 字段的目錄或文件都不會被自動打進 rpm 包里。反之如果你在任何 %files 字段指定了虛擬根目錄里并不存在的東西,系統(tǒng)就會報錯,包括用 %exclude 排除的東西也是這樣。通常我們只需要在 %files 字段指定所有頂層目錄就可以了。若要了解軟件到底向系統(tǒng)內安裝了哪些目錄和文件,你可以采取下列辦法: 1. 在 %files 字段內只寫進 %{_prefix}: %files %defattr(-,root,root) %{_prefix} 這樣所有東西都將被打進 rpm 包。打好包之后,用如下命令查詢生成的 rpm 包的目錄結構: rpm -qpl xxx.rpm 2. 打包前手工執(zhí)行配置、安裝,當 ./configure 執(zhí)行后,重定向安裝到一個虛擬根目錄里。例如(注意大小寫): ./configure make (這步可以省略,不信就試試) make DESTDIR=/var/tmp/xxx install 或者 make prefix=/var/tmp/xxx install 然后進入 /var/tmp/xxx 目錄查看里面的目錄結構: cd /var/tmp/xxx tree 3. 打包前手工執(zhí)行配置、安裝,當 ./configure 執(zhí)行后,查看生成的 Makefile 的 install 字段。注意:如果軟件不符合 GNU 規(guī)范,可能并沒有提供 configure 腳本,而是直接提供了 Makefile。這些通常都是游戲軟件。這比較復雜,如果你不懂編程,可能看不懂 Makefile。 :lol: 注5: 補丁通常是這樣創(chuàng)建的: diff -Nur directory.old directory.new > xxx.patch directory.old 代表舊源代碼目錄,directory.new 代表修改過的新源代碼目錄。 這里有一個由壓縮包直接創(chuàng)建 rpm/srpm 包的工具,但是它無法知道那些文件、目錄應該被打進包里,你需要指定: http:///project/show...release_id=7939 下面是一個實際例子,更多范例可以瀏覽這里: http://www./people/kde/magic/specs/ -------------------------------------------------------------------- Summary: KDE graphics package Name: kdegraphics Version: 3.3.0 Release: 2mgc Copyright: GPL URL: http://www. Group: desktop/kde BuildRoot: %{_tmppath}/%{name}-%{version}-%{release}-root Source: %{name}-%{version}.tar.bz2 Prefix: %{_prefix} Requires: qt, arts, kdelibs, kdebase, liblcms, fribidi Packager: kanker <這里填寫 kanker 的實際郵件地址,為防垃圾郵件,我把它去掉了> %description Graphic applications for the K Desktop Environment. provide some useful tools like ksnapshot,kpaint and so on. %package devel Summary: Development files for kdegraphics Requires: %{name} Group: Development/Libraries Provides: kviewshell-devel Provides: libkscan-devel %description devel Graphic applications for the K Desktop Environment. This package contains header files for developing applications using kdegraphics. %prep %setup -q -n %{name}-%{version} %Build rm -rf kcoloredit rm -rf kpdf rm -rf kruler rm -rf kgamma rm -rf kuickshow rm -rf kview make -f admin/Makefile.common cvs ./configure --prefix=%{_prefix} --enable-final --disable-debug \ --with-extra-includes=%{_includedir}/freetype2 --includedir=%{_includedir} make %install rm -fr $RPM_BUILD_ROOT make DESTDIR=$RPM_BUILD_ROOT install cp -r $RPM_BUILD_ROOT%{_datadir}/apps/kolourpaint/icons/hicolor/* $RPM_BUILD_ROOT%{_datadir}/icons/crystalsvg/ %clean rm -rf $RPM_BUILD_ROOT rm -rf $RPM_BUILD_DIR/%{name}-%{version} %files %defattr(-,root,root) %{_bindir} %{_libdir} %{_datadir} %exclude %{_libdir}/debug %files devel %defattr(-,root,root) %{_includedir} %changelog * Sun Oct 3 2004 kde <這里填寫實際郵件地址> - fix the spec file and rebuild * Sat Oct 2 2004 kanker <這里填寫實際郵件地址> - initialize the first spec file |
|