作者:雨亦奇 ,趙建利 要想制作一個RPM格式的軟件包,需要編寫軟件包描述文件。其標准命名格式為:軟件名-版本號-釋出號.spec,這個文件,詳細描述了有關該軟件包的諸多信息,如軟件名,版本,類別,說明摘要,創建時要執行什麼指令,安裝時要執行什麼操作,以及軟件包所要包含的文件等等。有了這個文件,RPM就可以制作出相應的包裹文件來。 下面以我制作小趙編輯器LZE的軟件包(lze-6.0-2.i386.rpm)為例,詳細說明一下軟件包描述文件的書寫。其描述文件為lze-6.0-2.spec,該文件內容如下:(用nl -ba命令列出,每行開頭的數字為所在行在文件中的行號) 1 # 文件名稱: lze-6.0-2.spec 2 # 文件功能: lze軟件包描述信息 3 # 文件作者: 縱橫軟件制作中心雨亦奇 國防大學研究生二隊趙建利 4 # 修改時間: 2001.10.19 5 6 Name: lze 7 Version: 6.0 8 Release: 2 9 Summary: 小趙全屏幕中英文多窗口多功能編輯器(Linux/UNIX系統適用) 10 Group: Applications/Editors 11 License: Share 12 Vendor: 縱橫軟件制作中心 13 Packager: 雨亦奇([email protected]) 14 Source: http://zhsoft.myetang.com/lze-6.0-2.src.tgz 15 Prefix: /usr 16 Requires: /bin/sh 17 Provides: lze-edit 18 19 %description 20 小趙編輯器,是為使用SCO UNIX,LINUX多用戶系統的廣大用戶專門設計的全屏幕多窗 21 口中英文多功能編輯器。 22 它主要有以下十大特點:1.全屏幕菜單操作。2.顯示方式多樣。3.塊操作豐富。4.十 23 字制表功能強大。5.多窗口操作靈活自如。6.文件操作功能齊全。7.解釋輸出功能獨具特 24 色。8.自帶中文輸入法(增強五筆和增強拼音),實用方便。9.十六進制編輯功能,如虎 25 添翼。10.即時翻譯,按到即譯。 26 總之,小趙編輯器會成為您在UNIX,LINUX系統上編制程序和書寫一般性文稿的好幫手。 27 它將在工作中助您一臂之力,輕松上陣,游刃有余! 28 29 %prep 30 echo "預處理腳本程序(prep)開始執行" 31 %setup 32 33 %build 34 echo "編譯連接腳本程序(build)開始執行" 35 make 36 37 %install 38 echo "安裝腳本程序(install)開始執行" 39 make install 40 41 %clean 42 echo "建包結束後清理腳本程序(clean)開始執行" 43 44 %pre 45 echo "安裝前執行腳本程序(pre)開始執行" 46 47 %post 48 echo "安裝後執行腳本程序(post)開始執行" 49 50 %preun 51 echo "卸載前執行腳本程序(preun)開始執行" 52 53 %postun 54 echo "卸載後執行腳本程序(postun)開始執行" 55 56 %veryfiscript 57 echo "軟件包校驗腳本程序(verifyscript)開始執行" 58 59 %triggerin -- xiuwu 60 echo "軟件包安裝時觸發腳本程序(triggerin)開始執行" 61 62 %triggerun -- yuntaishan < 2.0 63 echo "軟件包卸載前觸發腳本程序(triggerun)開始執行" 64 65 %triggerpostun -- dapubu 66 echo "軟件包卸載後觸發腳本程序(triggerpostun)開始執行" 67 68 %files 69 %defattr (-,root,root) 70 %config /etc/funkey.def 71 %config /etc/inputme.def 72 %doc /usr/doc/lze-6.0/README 73 %doc /usr/doc/lze-6.0/LICENSE 74 /usr/bin/lze 75 /usr/bin/lzeime.py 76 /usr/bin/lzeime.wb 77 /etc/wbzc.dat 78 79 %changelog 80 * Tue Aug 18 1998 雨亦奇 81 - 內置拼音,五筆輸入法 82 * Fri May 01 1998 雨亦奇 83 - 增加多窗口操作 84 * Mon Mar 24 1997 雨亦奇 85 - 增加塊操作命令 86 該描述文件包括以下幾方面的內容: 一、注釋行 見第1-4行。 它以#號開頭,起注解作用,可幫助用戶理解所寫的內容,但對軟件包的生成不起任何作用。此文件中,注釋行集中在文件首部。實際上,它可位於描述文件的任何位置。 二、文件頭 見第6-17行。 文件頭描述軟件包的基本信息,它包含若干個域,其中有必選的域,也有可選的域。一個域占用一行,其描述格式為: 域名 : 域值 注意: 域名不分大小寫,並且域值不能為空。 文件頭必選域有以下六個: 1. Name : 此域定義軟件名。 2. Version : 此域定義版本號。僅當軟件較以前有較大改變時才增加版本號。注: 版本號中不能含減號(-)字符。 3. Release : 此域定義釋出號。若軟件較以前改變較小,則僅增加釋出號,不改變版本號。注: 釋出號中亦不能含減號(-)字符。 RPM利用上述的Name(軟件名),Version(版本號),Release(釋出號)及體系號來命名軟件包,如本例輸出的包裹文件名為lze-6.0-2.i386.rpm。 4. Summary : 此域定義軟件包簡介,為一句話說明。 5. Group : 此域定義軟件所屬類別,詳見<<精通RPM之五--查詢篇>>,本例的Applications/Editors表示本軟件屬"應用/編輯器"類。 6. License : 此域定義軟件適用的許可證或版權規則。該域也可用Copyright(版權)來定義,二者同意。許可證具體有: GPL(通用公共許可證,自由軟件適用),BSD,MIT,Public Domain(公共域),Distributable(貢獻),Commercial(商業),Share(共享)等。 文件頭可選的域包括如下幾類: 1. 基本信息 1.1 Vendor : 此域定義軟件的供應商(銷售商)。 1.2 Distribution : 此域定義軟件所屬的發行版,這是軟件包制作者自己的分類。通常,一個發行版由若干個軟件包構成。如我想做一個名為“熊貓'95”的發行版,則其中每個軟件包(如竹葉95)的描述文件都應有這麼一行: Distribution : 熊貓'95 1.3 Icon : 此域指定軟件包所用的圖標文件名。此文件為GIF或XPM格式,必須存放在RPM的%_sourcedir(源碼目錄)宏所指示目錄下,默認為/usr/src/dist/SOURCES。RPM本身並不使用圖標,但它將圖標文件內容存貯到包裹文件中,安裝時亦存貯到RPM數據庫中。此圖標可被圖形界面的RPM包管理工具使用,用以改善界面效果,增加可視性。如下例指示軟件包使用panda.xpm作為圖標: Icon : panda.xpm 1.4 Packager : 此域定義打包者,亦即建立此軟件包的人或公司。書寫格式是: 打包者的名字 <電子信箱或相關網頁> 請參考描述文件第13行。 1.5 Serial : 此域定義軟件序列號,也可使用域名Epoch。軟件序列號為一整數,由打包者指定,它應隨著版本號的增加而不斷增加,並且始終保持數值的唯一。軟件序列號可被用來說明軟件包之間的依賴關系。下例指定軟件包序列號為4: Serial : 4 或用: Epoch : 4 1.6 URL : 此域定義包含打包軟件有關信息的網頁地址。如: URL : http://devplanet.fastethernet.net/gxedit.Html 2. 依賴相關 依賴是RPM用來描述軟件包之間關系的。一個軟件包依賴的東西RPM稱作功能,它可以是真實存在的軟件包,也可以是虛擬的軟件包(虛包)。虛包沒有版本號。 依賴相關的域有: 2.1 Provides : 此域定義軟件包提供的功能,可重復多行。其描述格式為: Provides : 功能1 [,功能2] ... 注: []所括為可選項,多個功能之間以逗號或空格分隔。 軟件包所提供的功能一般是以虛包形式存在的共享庫。當有多個軟件包均提供相同的服務時,常用虛包來表示其服務。如,一個郵件客戶端軟件允許用戶使用不同的看信方式(文本形式,HTML形式等),可以要求任何一個看信程序必須提供mail-reader虛包。這樣,看信程序的描述文件應有這麼一行: Provides : mail-reader 如此它才能被郵件客戶端使用。 2.2 Requires : 此域定義軟件包所需的功能,可重復多行。其描述格式為: Requires : 功能1 [比較符1 [序列號1:]版本號1[-釋出號1]] [,功能2 [比較符2 [序列號2:]版本號2[-釋出號2]]] ... 其中: * []所括為可選項; * 比較符可使用<(小於),>(大於),=(等於),>=(大於等於)或<=(小於等於); * 序列號不選時,RPM默認為0; * 功能之間的逗號可選,也可使用空格進行分隔。 例子:Requires: aaa, bbb >= 3.0, ccc < 2:5.0-1 注: 本例定義生成的包在安裝時需要系統有如下功能: (1) aaa(系統中已安裝aaa包,或者已安裝軟件包中有軟件包提供aaa虛包); (2) bbb包已安裝且版本要求大於等於3.0; (3) ccc包已安裝且版本要求小於序列號為2,版本號為5.0且釋出號為1。 RPM在進行版本比較時,執行比較的順序是; 先版本號,再釋出號,最後比較序列號。通過比較,確定哪個版本較新,哪個版本較老。 2.3 Conflicts : 此域定義有哪些功能與本軟件包相沖突(不能共存)。此域亦可在描述文件中書寫多次。其描述格式形同Requires域,為: Conflicts : 功能1 [比較符1 [序列號1:]版本號1[-釋出號1]] [,功能2 [比較符2 [序列號2:]版本號2[-釋出號2]]] ... 其中: * []所括為可選項; * 比較符可使用<(小於),>(大於),=(等於),>=(大於等於)或<=(小於等於); * 序列號不選時,RPM默認為0; * 功能之間的逗號可選,也可使用空格進行分隔。 舉個例子: Conflicts : xxx=1:2.0 yyy>=3.0 注: 本例闡明生成的包沖突的功能有: (1) 當系統中xxx包版本等於序列號為1且版本號為2.0時;(2) 當系統中yyy包版本大於等於3.0時。 *** 依賴關系的自動實現 *** 一般情況下,當RPM建立一個軟件包時,它要執行/usr/lib/rpm目錄下的兩個小程序。一個是find-requires,用於查找軟件包所需的共享庫,這些庫將以虛包的形式加入到該軟件包所需的功能(Requires)之中。另一個是find-provides,它用於查找軟件包所提供的共享庫,這些庫將以虛包的形式加入到該軟件包所提供的功能(Provides)之中。這兩個程序都是SHELL程序,代碼量雖小,但確實幫了軟件包制作者一個大忙--不必勞心費神地自己寫這樣的依賴關系了,因為程序均自動完成了。 下面三個域用於指示RPM是否執行這兩個程序。 2.4 Autoreq : 此域用於指示RPM是否自動查找軟件所需的共享庫。僅當域值為no或0時,RPM不執行find-requires程序,否則均執行該程序。 2.5 Autoprov : 此域用於指示RPM是否自動查找軟件提供的共享庫。僅當域值為no或0時,RPM不執行find-provides程序,否則均執行該程序。 2.6 Autoreqprov : 此域用於指示RPM是否自動查找軟件所需的共享庫與其提供的共享庫。僅當域值為no 或0時,RPM不執行find-requires與find-provides兩個程序。此域相當於同時設定Autoreq 與Autoprov域值為指定之值。 注: 上述三個域在描述文件中,它們之間因為順序的不同而結果會有所不同,一般以最後一個為准。如: Autoreq : yes Autoreqprov : no Autoprov : yes 注: 本例雖然第一行允許執行find-requires,但第二行又不允許find-requires與find-provides兩個程序運行,而第三行允許find-provides運行,所以依照執行順序,結果為不允許執行find-requires,而允許執行find-provides。 又如: Autoreq : no Autoreqprov : yes Autoprov : no 注: 本例的結果為允許執行find-requires,而不允許執行find-provides。 3. 系統相關 RPM制作軟件包時,可以為其指定適用的CPU體系或操作系統,也可為其指定不適用的CPU體系或操作系統,這樣,當RPM發現當前的CPU體系或操作系統與軟件包要求的不兼容時,將中止軟件包的制作。RPM默認的當前CPU體系由宏%_arch定義,一般為i386。RPM默認的當前操作系統由宏%_os定義,一般為linux。讀者可以通過查看/usr/lib/rpm/macros宏定義文件得到。 下面四個域說明軟件包的適用范圍: 3.1 Excludearch : 此域定義軟件包不適用的體系。RPM可選的體系名請參見/usr/lib/rpm/rpmrc文件中的arch_canon項目。 軟件包不適用於某個體系,可能有兩方面的原因。一是該軟件還沒有移植到所定義的體系上;二是該軟件含有特定的機器碼(匯編語言),它與別的體系不兼容。 此域描述格式為: Excludearch : 體系1 [體系2] ... 注: []所括為可選項,各體系之間以空格分隔。 如果當前體系在此域值之中,則RPM制作軟件包時將報錯退出,請看下面的例子。 在lze-6.0-2.spec文件頭部分加入一行: Excludearch : i386 再運行建包命令rpm -bb(<<精通RPM之七--制作篇(下)>>將講到): # rpm -bb lze-6.0-2.spec Architecture is excluded: i386 # 由上看出,RPM提示了“體系不適用: i386”的錯誤。 3.2 Exclusivearch : 此域定義軟件包適用的體系。其描述格式與Excludearch類似: Exclusivearch : 體系1 [體系2] ... 注: []所括為可選項,各體系之間以空格分隔。 假如在lze-6.0-2.spec文件頭加入一行: Exclusivearch : i386 sparc 再運行建包命令將會怎麼樣: # rpm -bb lze-6.0-2.spec Executing: %prep 預處理腳本程序(prep)開始執行 Executing: %build 編譯連接腳本程序(build)開始執行 Executing: %install 安裝腳本程序(install)開始執行 Processing files: lze Finding Provides: (using /usr/lib/rpm/find-provides)... Finding Requires: (using /usr/lib/rpm/find-requires)... Provides: lze-edit PreReq: /bin/sh Requires: /bin/sh ld-linux.so.2 libc.so.6 libc.so.6(GLIBC_2.0) libc.so.6(GLIBC_2.1) Wrote: /usr/src/dist/RPMS/i386/lze-6.0-2.i386.rpm # 看,此次建包(lze-6.0-2.i386.rpm)成功了,因為當前的體系(i386)正好適用。 3.3 Excludeos : 此域定義軟件包不適用的操作系統。RPM可選的操作系統請參考文件/usr/lib/rpm/rpmrc中的os_canon項目。 其描述格式為: Excludeos : 操作系統1 [操作系統2] ... 注: []為可選項,操作系統之間以空格分隔。例如: Excludeos : irix aix solaris 注: 如將此行加入到lze的描述文件中,則它會指示RPM不在irix,aix,solaris這三個操作系統上建立lze軟件包。如果當前操作系統是三者之一,則RPM會報錯並中止軟件包的制作。 如: # rpm -bb lze-6.0-2.spec OS is excluded: Solaris # 3.4 Exclusiveos : 此域定義軟件包適用的操作系統。其描述格式為: Exclusiveos : 操作系統1 [操作系統2] ... 注: []為可選項,操作系統之間以空格分隔。例如: Exclusiveos : linux solaris 4. 目錄相關 4.1 Prefix : 此域定義可重定位的目錄前綴,可在描述文件中書寫多次。其描述格式為: Prefix : 目錄前綴1 [目錄前綴2] ... 注: []為可選項,各目錄前綴之間均以空格分隔。例如: Prefix : /usr /etc 它也可寫作: Prefix : /usr Prefix : /etc RPM利用可重定位的目錄前綴,實現了軟件包的重定位安裝,使軟件中的文件不必固定在某個絕對位置,這種做法很好。LZE軟件包描術文件lze-6.0-2.spec中就定義了一個可重定位的前綴/usr(見第15行),這樣,安裝時就可將該包中在/usr目錄下的文件重定位到用戶指定的目錄,如: # rpm -i --prefix /tmp lze-6.0-2.i386.rpm # 或者: # rpm -i --relocate /usr=/tmp lze-6.0-2.i386.rpm # 注: 此命令安裝lze包,將其中含/usr重定位目錄前綴的文件定位到/tmp目錄。如包中 的/usr/bin/lze文件安裝後,因重定位而成了/tmp/bin/lze。(RPM安裝命令使用方法請參考<<精通RPM之二--安裝篇>>) 4.2 Buildroot : 此域定義的是軟件包所包含的文件共有的根目錄,此根目錄僅供RPM建立軟件包時使用。即當RPM建立軟件包時,將設定此目錄為根(調用chroot函數),提取所需文件,生成軟件包。 例如: 當Buildroot設定為/tmp時,對於LZE包描述文件中所包含的/usr/bin/lze文件,RPM實際打包的則是/tmp/usr/bin/lze,但對生成的包查詢後可以發現:原文件名並未改變,還是/usr/bin/lze。 如此說來,這就很有意思了。一般用戶通過設定Buildroot,也可以象超級用戶(root)那樣自由地建立各種各樣的軟件包了,即使包中有那些唯有超級用戶才可以操作的目錄或文件。安裝這樣的包與安裝由超級用戶建立的包,是沒有什麼分別的。 此域的描述格式很簡單: Buildroot : 目錄 如,上例可定義為: Buildroot : /tmp 5. 源碼相關 下列四個域均是為制作源碼包而設計的。源碼包裡有什麼?用戶可以通過查詢包的文件列表得到,命令是“rpm -qpl 源碼包文件”(請參閱<<精通RPM之五--查詢篇>>有關內容)。一般情況下,源碼包裡有這麼四類文件: 一是程序源碼(SOURCE),二是源碼補丁(PATCH),三是軟件包描述文件,四是圖標文件(ICON)。通過安裝源碼包,用戶可以輕松地實現現場編譯、連接和應用,同時更方便了軟件開發者與軟件包制作者:他們維護程序容易了,並且維護過後可以很快地生成執行代碼包與源碼包。這,也是所有人鐘愛RPM的重要原因之一。 5.1 Source : 此域定義RPM打包時要包含的程序源碼文件。這些文件一般先用tar命令打包,然後再用gzip壓縮。一個描述文件中可包含多個Source域,當有多個這樣的域時,需要進行編號:第1個編為Source0(也可直接用Source),第2個編為Source1,第3個編為Source2等等。此域的描述格式為: Source[編號] : 源碼文件 注: []所括為可選項。具體用法如: Source0 : lze-6.0-2.tar.gz Source1 : lzeime-wb-6.0-2.tar.gz Source2 : lzeime-py-6.0-2.tar.gz Source3 : lze-lib-6.0-2.tar.gz 注: 此域域值可以采用URL(統一資源定位)的形式,如LZE描述文件第14行。采用這種形式,主要是給其它用戶提供該源碼的位置信息。在RPM制作源包時,它提取的是最後的文件名lze-6.0-2.tar.gz,而不是http://zhsoft.myetang.com/lze-6.0-2.tar.gz(URL前面的內容被RPM忽略了)。 5.2 NoSource : 在上例中,假如在打包時不想包含Source1與Source2定義的文件,那該怎麼辦? 辦法之一是將其所在行刪除掉; 辦法之二是將其所在行注釋掉(即所在行前面加#號); 辦法之三就是定義Nosource域,此域可重復。其描述格式為: NoSource : 源碼域編號 本例可寫作: NoSource : 1 NoSource : 2 注: 其中的1與2為編號,表示Source1和Source2。 注意: 如果軟件包描述文件中沒有NoSource域,則RPM生成的源碼包名字格式為"軟件名-版本號-釋出號.src.rpm"。如果使用了NoSource域,則RPM生成的源碼包名字格式為"軟件名-版本號-釋出號.nosrc.rpm"(單從名字就可看出源碼包包含的文件不完整)。 5.3 Patch : Patch的本義是補丁,用在這裡指的是源程序的補丁,它是用diff命令比較新老源程序所產生的輸出(命令為“diff -Nur 舊文件 新文件 >補丁文件”),而系統中的patch命令又可利用此輸出將老版本的源程序升級為新版本。 此域定義RPM制作源碼包時所要包含的補丁文件,該文件的命名建議用"軟件名-版本號.補丁功能.patch"的格式。一個軟件包描述文件中可有多個Patch域,當有多個這樣的域時,也需要象Source域那樣進行編號(注:第1個域編為Patch0,也可省略0,用Patch)。 此域的描述格式為: Patch[編號] : 源碼補丁文件 注: []所括為可選項。具體用法如: Patch0 : blather-4.5-bugfix.patch Patch1 : blather-4.5-config.patch Patch2 : blather-4.5-somethingelse.patch 注: 此域的域值也可以象Source域一樣,采用URL的形式,RPM僅提取其中的文件名供其使用。 5.4 NoPatch : 此域的功能類似NoSource,其定義的編號對應的補丁文件RPM不作打包處理。此域在描述文件中可重復出現。如上例,若不想讓源碼包包含Patch0與Patch2域所指示的補丁文件,則可在描述文件寫上這麼兩行: NoPatch : 0 NoPatch : 2 注意: 如果軟件包描述文件中沒有NoPatch域,則RPM生成的源碼包名字格式為"軟件名-版本號-釋出號.src.rpm"。如果使用了NoPatch域,則RPM生成的源碼包名字格式為"軟件名-版本號-釋出號.nosrc.rpm"(單從名字就可看出源碼包包含的文件不完整)。 三、功能段 見第19-86(即文件頭以下的部分)。 何謂功能段?可以這麼說,功能段是描述軟件包的重要數據和操作指令的段落,它包括段名與段內容兩部分。沒有功能段,RPM便制作不出任何包裹文件。功能段的段名都是以百分號(%)開始的,占用一行。功能段的段內容范圍是這樣界定的:它從該功能段段名下一行開始到下一個功能段段名的前一行或到描述文件結束。如LZE描述文件,%description段是從第19行到第28行(%prep段從第29行開始),第19行為段名,第20-28行為段內容。而%prep段是從第29行到第32行(第33行%build段開始),其段名在第29行,段內容在第30-32行。另外要注意的是,各個功能段的位置是自由的,可放在文件頭以下的任何位置,不必拘泥某一固定位置。 必選的功能段 描述文件中,必選的功能段有: 1. %description 本段是描述段,段的內容是對軟件包進行較為詳細的介紹,不象文件頭的Summary域僅用一句話說明。介紹的文本形式自由,可任意換行,不受限制。具體請參見LZE描述文件第20-27行。 本段段名描述格式是: %description [子包選項] 其中,子包選項的格式為:[-n] 子包名 注: []所括為可選項。 三種形式的描述段段名: (1) 段名格式為“%description”時: 本功能段描述的內容是關於父包的。父包也可叫作主軟件包,它用軟件名來命令,其名字格式是:軟件名-版本號-釋出號.體系.rpm。如:lze-6.0-2.i386.rpm。 (2) 段名格式為“%description 子包名”時: 本功能段描述的內容是關於子包的。子包選項中沒有-n選項時,子包是用軟件名加子包名的形式命名,格式為: 軟件名-子包名-版本號-釋出號.體系.rpm。如分成兩個子包的LZE軟件:lze-bin-6.0-2.i386.rpm(執行程序包),lze-config-6.0-2.i386.rpm(配置文件包)。 (3) 段名格式為“%description -n 子包名”時: 本功能段描述的內容也是關於子包的。當子包選項中有-n選項時,子包直接采用子包名的形式命名。它不包含軟件名,命名格式為: 子包名-版本號-釋出號.體系.rpm。如分成兩個子包的LZE軟件: bin-6.0-2.i386.rpm(執行程序包),config-6.0-2.i386.rpm(配置文件包)。注意:這種類型的子包內容通常是可被其它軟件包共用的函數庫,如果專用,則盡量不要采用這樣形式來定義子包。 2. %files 本段是文件段,它定義的是軟件包需要包含哪些文件。本段通常放在描述文件尾部,以便於添加文件名,便於編輯。 本段段名描述格式為: %files [子包選項] [-f 文件名] 注: []所括為可選項。 當沒有任何選項時,本段內容定義的是父包要打包的文件列表; 當有子包選項時,本段內容定義的則是子包要打包的文件列表; 當選擇-f選項時,RPM除了從文件段讀取打包文件列表外,還將從指定的文件中讀取要打包的文件列表。指定的文件中,一個文件名占用一行。此選項方便了軟件包制作者,他們可以通過程序自動產生有關軟件的文件列表,並將其寫入到一個特定的文件中,這樣制作軟件包時,只需引用一下這個文件,RPM就會自動從這個文件中讀取文件名並將其加入包中。如果沒有此選項,軟件包制作者只能在文件段裡,將要打包的文件名一個一個寫進去,有點麻煩。 文件段的內容格式為: [修飾符1 [修飾符2] ...] 文件名 其中:修飾符是可選的,一個文件可以有多個修飾符,文件名必須以/開頭(絕對路徑形式)。 修飾符有以下幾類: (1) 文件相關 * %doc : 此修飾符設定文件類型為說明文檔(參見LZE描述文件第72,73行); * %config : 此修飾符設定文件類型為配置文件(參見LZE描述文件第70,71行); * %config(missingok) : 此修飾符設定文件類型為配置文件,且此文件可丟失。即使丟失了,RPM在卸載軟件包時並不認為這是個錯誤,並不報錯。 此修飾符通常用於那些軟件包安裝後建立的符號連接文件,如/etc/rc.d/rc2.d/S55named等。此類文件在軟件包卸載後可能需要刪除,所以丟失了也不要緊。 * %config(noreplace) : 此修飾符設定文件類型為配置文件,且如果安裝時系統中有同名的文件,則軟件包中的這個文件將換個名字安裝,其文件名後綴加個.rpmnew。(如果不用此修飾符,則安裝時RPM若發現有同名文件,則RPM會將系統中的這個文件換個名字,其後綴加上.rpmorig,而軟件包中的文件則還用原來的名字。)在軟件包卸載時,系統中的同名文件被RPM換個名字保存起來,其後綴加上了.rpmsave。 如描述文件的文件段中定義了這麼一行: %config(noreplace) /etc/hello 則制成的包在安裝時,若系統中已有此文件/etc/hello,則RPM會提示: warning: /etc/hello created as /etc/hello.rpmnew 這表明包中的/etc/hello文件被創建為/etc/hello.rpmnew文件了。 如果卸載這個軟件包,則系統中的/etc/hello將會改名為/etc/hello.rpmsave。 * %Ghost : 此修飾符所修飾的文件,其內容不被包含到軟件包中。這樣的文件一般是日志文件(log file)一類的文件,其文件屬性(文件名,屬主,屬組等)很重要,但是文件內容並不重要。用此修飾符後,RPM僅將其文件屬性加入包中。 * %attr : 此修飾符設定文件的屬性信息,使用格式為: %attr(權限,屬主,屬組) 注: 權限常用數字形式(八進制),屬主和屬組可以是數字,也可以是字符串。如果文件的權限,屬主和屬組想使用系統默認值,則可用減號(-)表示它。 如下例采用兩個修飾符,定義/etc/funkey.def文件的權限為755,屬主默認,屬組為root,類型為配置文件: %attr(755,-,root) %config /etc/funkey.def * %verify : 此修飾符設定文件需要校驗的那些屬性。這些屬性有:owner(屬主),group(屬組),mode(權限),md5(MD5檢查和),size(大小),maj(主設備號),min(從設備號),symlink(符號連接),mtime(最後修改時間)。 此修飾符使用格式為: %verify([not] owner group mode md5 size maj min symlink mtime) 注: not可選。當選用not時,表明需要校驗除選定屬性以外的那些屬性。 如下例指示RPM校驗/dev/ttyS0文件時,要校驗其權限,MD5檢查和,大小,主設備號,從設備號,符號連接和最後修改時間共七項屬性信息: %verify(mode md5 size maj min symlink mtime) /dev/ttyS0 這也可以采用not選項來實現,因為除去屬主owner和屬組group兩項屬性,剩下的就是需要校驗的屬性了: %verify(not owner group) /dev/ttyS0 (2) 目錄相關 * %docdir : 此修飾符定義說明文檔前綴,這樣,後面所有含指定文件名作為前綴的文件,RPM打包時會將其類型統一設定為說明文檔。 例如某描述文件的文件段中有這麼三行: /root/readme %docdir /root /root/mydoc.txt 此例指明/root為說明文檔的前綴,因為/root/mydoc.txt在%docdir的下一行,所以RPM打包時會設定此文件的類型為說明文檔。而/root/readme文件則不做此設定,因為它在%docdir定義之前。 通過此修飾符,用戶可以很方便地設定說明文檔一類的文件,因為它們通常固定在某個目錄下面,有著共同的前綴。 * %dir : RPM在制作軟件包時,如果要打包的文件是個目錄,那麼RPM會將該目錄下面的所有文件包含到軟件包中。(注意:如果要打包的文件是個符號連接,此符號連接又指向一個目錄,則RPM並不會將其視作目錄,只會把它當為普通文件處理。)如果僅想將這個目錄名包含到軟件包中,制作者用此修飾符修飾一下這個目錄名就行了。 如: /etc是個系統目錄,其下有多個文件,如果想將其均加入包中,描述文件的文件段裡可寫上這麼一行: /etc 如果僅想包含此目錄,則可用: %dir /etc (3) 另類修飾符 此類只有一個%defattr。說它是另類修飾符,是由於它設定的是默認的文件屬性,而非特定的某個文件。它一般放在文件段內容的第一行。 其使用格式為: %defattr(權限,屬主,屬組) 其中: 權限,屬主和屬組都可以使用減號(-)。使用減號的屬性將由系統設定。 例如: %defattr(022,zzz,zhsoft) 設定其後的所有文件權限為022,屬主為zzz,屬組為zhsoft;又如: %defattr(-,zzz,-) 則是設定其後的所有文件屬主為zzz,權限與屬組由系統設置。 可選的功能段 描述文件中,可選功能段的內容都是些腳本程序。(LZE描述文件中多個腳本程序中僅含一個echo命令) 可選的功能段的描述格式為: 功能段名 [子包選項] 注: 子包選項為"[-n] 子包名"。當無子包選項時,段內容描述的是父包的腳本程序。當有子包選項時,段內容則是描述子包的腳本程序。 可選的功能段可分為如下三類: 1. 建包用功能段: RPM通過源程序來建立一個軟件包時,要執行預處理,編譯,安裝和清理四項操作,分別對應於%prep,%build,%install和%clean四個段。 下面按其執行順序逐段進行說明: 1.1 %prep : 此為預處理段,其內容為預處理腳本程序。該程序完成以下任務: * 建立軟件編譯用目錄; * 將源程序解壓縮; * 通過打補丁,升級源程序; * 執行其它一些操作,使源程序隨時可進行編譯。 在此腳本程序中,可使用如下兩個宏命令: 1.1.1 %setup 這個宏利用系統中的gzip與tar等命令,來解壓源程序包。RPM會自動探測源程序包是否壓縮,如果壓縮,它會用gzip將其解壓縮,否則直接用tar命令展開包中文件。其使用格式為: %setup [-n name] [-c] [-D] [-T] [-b N] [-a N] 注: []所括為可選項。 (1) 當沒有任何選項時: 這個宏用來解壓默認的源程序包(由文件頭Source或Source0域指定)。注意:源程序包中的文件應用"軟件名-版本號"作為其上層目錄,這樣%setup宏就可以正常工作。如果不以"軟件名-版本號"作為其上層目錄,則%setup宏工作時有一個指令"cd 軟件名-版本號"(轉目錄)會因為系統中沒有此目錄而出錯退出(除非在此宏上面加上建立此目錄的命令)。如LZE軟件源程序所在的目錄為lze-6.0,我需要用命令"tar cvzf lze-6.0-2.src.tgz lze-6.0"將源程序打包並壓縮,這樣的包就可以被%setup宏正確使用了。 下面是%setup宏命令所執行的一系列命令: (指令前面為行號) 1 cd /usr/src/dist/BUILD 2 echo "預處理腳本程序(prep)開始執行" 3 cd /usr/src/dist/BUILD 4 rm -rf lze-6.0 5 /bin/gzip -dc /usr/src/dist/SOURCES/lze-6.0-2.src.tgz tar -xvvf - 6 STATUS=$? 7 if [ $STATUS -ne 0 ]; then 8exit $STATUS 9 fi 10 cd lze-6.0 11 [ `/usr/bin/id -u` = '0' ] && /bin/chown -Rhf root . 12 [ `/usr/bin/id -u` = '0' ] && /bin/chgrp -Rhf root . 13 /bin/chmod -Rf a+rX,g-w,o-w . 14 exit 1 看,第10行就有一個轉到lze-6.0目錄的命令,如果沒有這個目錄,程序就會出錯退出了。也許你要問:這些指令你是怎麼知道的?其實這很簡單,只要在%setup宏下面加上一句"exit 1"命令,讓預處理腳本程序非正常退出即可。這樣RPM所執行的預處理腳本程序作為臨時文件在其退出時並未刪除,只要看一下這個文件(在/var/tmp目錄下以rpm-tmp開頭)就知道%setup宏命令做什麼了。 (2) -n name : 上面已經談到,源程序包中的文件應采用"軟件名-版本號"作為上層目錄。如果用了別的什麼目錄(如name),%setup宏無法正常工作,那該怎麼辦?沒關系,可以用-n選項,引用一下這個目錄(name)就行了。假如我的LZE源程序包中的文件是以lze為上層目錄,那麼我就可以用"%setup -n lze"宏命令來解壓縮該包。 (3) -c : 此選項的作用是創建上層目錄("軟件名-版本號"目錄)並轉到這個目錄。對於LZE軟件,其效果相當於在上例的第4行與第5行之間加上這麼兩行命令: mkdir -p lze-6.0 cd lze-6.0 它適用的情況是:有的源程序包是在源程序所在目錄下打的包,所以其中的文件都沒有上層目錄。這樣的話,要想正確解壓,必須創建上層目錄。 (4) -D : 本選項的作用是在解壓源程序包之前不要刪除軟件的上層目錄(軟件名-版本號)。在上例中,其效果是不執行第4行的命令(rm -rf lze-6.0)。 (5) -T : 本選項的作用是不解壓默認的源程序包(由文件頭的Source或Source0域所定義)。在上例中,其效果是不執行第5-9行的命令:第5行是解壓源程序包(用gzip -dc將包的內容解壓縮到管道中,再由tar -xvvf -從管道中讀取數據並展開),第6-9行是檢查解壓命令的返回值,非0時執行非正常退出。 (6) -b N : 本選項指示RPM在轉到上層目錄前解壓第N個源程序包(由文件頭SourceN域定義)。這適用於含上層目錄的源程序包。注意:如果使用此選項時不同時使用-T選項,則RPM解壓的是兩個源程序包,一個是默認的包(由Source或Source0域定義),一個是-b選項指定的包(由SourceN域定義)。這樣,當N等於0時,默認的源程序包將被解壓兩次。所以,如果想僅解壓指定源程序包,請同時使用-T選項,以禁止解壓默認的源程序包。 下面的宏命令僅解壓第1個源程序包,然後轉到上層目錄: %setup -b 1 -T (7) -a N :本選項指示RPM在轉到上層目錄後再解壓第N個源程序包(由文件頭SourceN域定義)。這適用於不含上層目錄的源程序包。使用本選項時,一般加上-c選項,以創建上層目錄並轉到此目錄。注意:如果使用此選項時不同時使用-T選項,則RPM解壓的是兩個源程序包,一個是默認的包(由Source或Source0域定義),一個是-a選項指定的包(由SourceN域定義)。這樣,當N等於0時,默認的源程序包將被解壓兩次。所以,如果想僅解壓指定源程序包,請同時使用-T選項,以禁止解壓默認的源程序包。 下面的宏命令讓RPM先轉到上層目錄,再僅解壓第2個源程序包: %setup -T -a 2 1.1.2 %patch 此宏利用系統中的patch命令,來給指定的源程序包打補丁,從而將程序升級。其使用格式為: %patch [-P N] [-p N] [-b name] [-E] 注: []所括為可選項。 為了說明下列選項的作用,我們為LZE軟件包描述文件中定義三個補丁文件: Patch0 : lze-patch.zero Patch1 : lze-patch.one Patch2 : lze-patch.three (1) 當沒有任何選項時: 沒有任何選項時,該宏使用的是默認的補丁文件(第0個補丁文件),即由文件頭Patch或Patch0域所定義的文件(LZE包使用lze-patch.zero)。 該宏在執行時,擴展為以下指令: echo "Patch #0:" patch -p0 -s < /usr/src/dist/SOURCES/lze-patch.zero 注: 第一行指令是利用echo命令向屏幕輸出字符串“Patch #0:”。第二行指令則是利用patch命令讀取補丁文件lze-patch.zero升級源程序。 patch命令用了兩個選項:(有關patch命令用法,詳見其用戶手冊) * -p : 這個選項用於確定patch所要操作的文件。它針對補丁文件頭部的文件名,刪除名字中指定數目個斜槓(/)前面的所有字符,從而得到要操作的文件名。如補丁文件裡有個文件名/usr/zzz/src/lze.c,則用-p0時patch操作的文件名不變,用-p1時則變為usr/zzz/src/lze.c,用-p2時則變為zzz/src/lze.c,如用-p4則操作的文件名變為lze.c。 * -s : 這個選項指示patch在打補丁過程中不輸出任何信息,即使有錯誤發生。 (2) -P N : 使用此選項以指示RPM使用第N個補丁文件(由文件頭PatchN域定義)。如想讓RPM使用LZE的第2個補丁文件Patch2(lze-patch.three)時,可使用"-P 2"來指定。 (3) -p N : 此選項與其參數是由%patch宏直接傳給patch命令的。請參見上面patch命令所用的-p選項的介紹。 (4) -b name : 當有多個patch命令操作同一個文件時,patch會將原文件換名保存(其後綴變作.orig),如lze.c會變作lze.orig。如果想用別的名字作後綴,則可用-b設置一下,這樣原文件會換名為"原文件名+後綴",如用-b ZZZ時,lze.c會換名保存為lze.cZZZ。 此選項在執行時,實際上是給patch命令傳遞了一個選項及參數,即--suffix name。 (5) -E : 此選項直接傳給patch命令,其作用是:如果一個文件打完補丁後內容為空(字節數為0),則刪除這個文件。 1.2 %build : 此為編譯段,其內容為編譯腳本程序。該程序完成源程序的編譯和連接。一個最簡單的例子就是程序中僅有一個make命令。這適用於大部分情況,因為多數軟件均有自己的makefile,這樣通過make命令就可實現編譯與連接。如果沒有makefile的話,需要軟件包制作者自己在編譯段書寫上一系列的編譯連接命令。 1.3 %install : 此為安裝段,其內容是安裝腳本程序。該程序將已編譯連接好的執行程序或其它文件存放到指定目錄下,這些程序或文件供RPM打包時使用。一個最簡單的例子就是程序中僅用一個make install命令,從而完成安裝。這也需要相應的軟件有makefile維護文件。沒有的話,軟件包制作者也得自己寫指令。 1.4 %clean : 此為清理段,其內容是清理腳本程序。此程序在RPM制作好軟件包後才執行,它通常是刪除那些編譯連接時產生的臨時文件或目錄,完成繕後工作。 2. 管理用功能段: 此類段用於軟件包自身的管理(安裝,卸載和校驗),包括%pre,%post,%preun,%postun,和%verifyscript五個功能段。 2.1 %pre : 該段內容為安裝前腳本程序。它在軟件包安裝之前執行,通常是檢測操作環境,建立有關目錄,清理多余文件等等,為軟件包的順利安裝做准備。本段很少使用。 其段名格式為: %pre [子包選項] 2.2 %post : 該段內容為安裝後腳本程序。它在軟件包安裝完成之後執行,常用來建立符號連接,修改系統配置文件,運行ldconfig程序等,以利軟件的正常運行。 其段名格式為: %post [子包選項] 2.3 %preun : 該段內容為卸載前腳本程序。它在軟件包卸載之前執行,主要為卸載做准備。具體如,要卸載的軟件包中某個程序當前正在運行時,此腳本程序必須殺掉它,否則無法正確卸載。 其段名格式為: %preun [子包選項] 2.4 %postun : 該段內容為卸載後腳本程序。它在軟件包卸載後執行,完成卸載的繕後工作,如將系統配置文件inetd.conf改回原來的樣子,重新運行一下ldconfig命令,將已卸載的共享庫從緩沖文件ld.so.cache中刪除等等。 其段名格式為: %postun [子包選項] 2.5 %verifyscript : 該段內容為校驗腳本程序。RPM校驗軟件包時,除了執行標准的校驗外,如果軟件包制作者設定有此校驗腳本程序,還將執行之。 其段名格式為: %verifyscript [子包選項] 下面是XFree86-libs-3.3.6-6.i386.rpm軟件包中的校驗腳本程序,它校驗的是動態鏈接庫目錄/usr/X11R6/lib。校驗時,在/etc/ld.so.cache文件中查找/usr/X11R6/lib,如果找不到,則顯示"missing",找到則顯示"found"。 # verifyscript echo -n "Looking for /usr/X11R6/lib in /etc/ld.so.conf... " if ! grep "^/usr/X11R6/lib$" /etc/ld.so.conf > /dev/null then echo "missing" echo "/usr/X11R6/lib missing from /etc/ld.so.conf" >&2 else echo "found" fi 3. 交互用功能段: 這類功能段有%triggerin,%triggerun,%triggerpostun,它們的內容都是RPM用於軟件包之間交互控制的腳本程序。這些腳本程序都是在系統滿足指定的條件下才觸發執行的: 1) %triggerin : 段內為安裝時觸發腳本程序,當其所在軟件包與指定軟件包僅有一方已安裝時,安裝另一方將觸發此程序執行; 2) %triggerun : 段內為卸載時觸發腳本程序,當其所在軟件包與指定軟件包都已安裝時,卸載二者中的任一個將觸發此程序執行; 3) %triggerpostun : 段內為卸載後觸發腳本程序,只有指定軟件包卸載後才觸發此程序執行。 3.1 段名格式 它們的段名描述格式均為: 交互段名 [子包選項] [-p 解釋程序] -- 觸發條件1 [,觸發條件2] ... 注: []所括為可選項。子包選項見前面介紹,不贅述。 3.1.1 -p選項: 此選項用於指定一個解釋程序,來解釋執行交互功能段的腳本程序。默認情況下,RPM使 用/bin/sh來執行腳本(此類腳本用SHELL語言編寫,也叫SHELL程序)。有的RPM包則是使用/usr/bin/perl 來執行腳本(此類腳本是用PERL這種解釋性語言寫的),這就需要用-p選項來指定解釋程序為 /usr/bin/perl,如: %triggerin -- sendmail ln -sf /usr/bin/sendmail /etc/mymailer/mailer %triggerin -- vmail ln -sf /usr/bin/vmail /etc/mymailer/mailer 注: 此例中定義package子軟件包安裝時觸發腳本程序:當觸發條件(fileutils>3.0,perl<1.2)滿足時,用/usr/bin/perl執行腳本,即用print命令輸出字符串"I'm in my trigger!"。 3.1.2 觸發條件: 交互功能段的觸發條件格式是: 功能名 [比較符 版本號] 其中:比較符與版本號可選。僅有一個功能名時,表明該功能存在時觸發程序執行。比較符可用大於(>),等於(=),小於(<),大於等於(>=)和小於等於(<=)。 如觸發條件bash,又如觸發條件fileutils>3.0,這種使用均合法。 交互功能段最少有一個觸發條件。當有多個觸發條件時,這些條件間均以逗號(,)分隔,它們之間是"或"的關系,即只要其中有一個條件系統滿足,RPM就將執行觸發腳本程序。如上面介紹-p選項時舉的例子:例子中有兩個觸發條件fileutils>3.0和perl<1.2,在安裝軟件包時,只要有一個條件滿足,RPM就會執行觸發腳本,即輸出"I'm in my trigger!"。 3.2 交互用功能段的使用 為什麼要使用交互用功能段?下面的例子很能說明問題。 假定mymailer軟件包需要/etc/mymailer/mailer這個符號連接文件指向當前使用的郵件發送代理程序。如果sendmail包安裝了,那麼這個符號連接文件應指向/usr/bin/sendmail程序。如果vmail包安裝了,那麼它應當指向/usr/bin/vmail程序。如果這兩個軟件包都安裝了(實際上,sendmail與vmail彼此是沖突的),那麼我們也無需考慮符號連接指向哪個文件了。當然,如果這兩個包都未安裝,那麼/etc/mymailer/mailer符號連接文件也沒有理由存在了。 上述要求,我們通過為mymailer軟件包編寫觸發腳本程序來實現,這些腳本程序在下列事件發生時,將改變/etc/mymailer/mailer符號連接的內容: 1) sendmail已安裝; 2) vmail已安裝; 3) sendmail卸載時; 4) vmail卸載時。 前兩個事件觸發的腳本程序可以這樣寫: %triggerin -- sendmail ln -sf /usr/bin/sendmail /etc/mymailer/mailer %triggerin -- vmail ln -sf /usr/bin/vmail /etc/mymailer/mailer 這是兩個安裝時被sendmail或vmail所觸發腳本程序。它們將在下列情況下執行: 1) 在mymailer包已安裝的情況下,安裝或升級sendmail包; 2) 在mymailer包已安裝的情況下,安裝或升級vmail包; 3) 在sendmail包已安裝的情況下,安裝或升級mymailer包; 4) 在vmail包已安裝的情況下,安裝或升級mymailer包。 後兩個事件觸發的腳本程序可以這麼寫: %triggerun -- sendmail [ $2 = 0 ] exit 0 if [ -f /usr/bin/vmail ] then ln -sf /usr/bin/vmail /etc/mymailer/mailer else rm -f /etc/mymailer/mailer fi %triggerun -- vmail [ $2 = 0 ] exit 0 if [ -f /usr/bin/sendmail ] then ln -sf /usr/bin/sendmail /etc/mymailer/mailer else rm -f /etc/mymailer/mailer fi 這兩個腳本程序在下列情況下觸發執行: 1) 在sendmail包已安裝的情況下,卸載mymailer包; 2) 在vmail包已安裝的情況下,卸載mymailer包; 3) 在mymailer包已安裝的情況下,卸載sendmail包; 4) 在mymailer包已安裝的情況下,卸載vmail包。 為了確保在mymailer包卸載後符號連接文件/etc/mymailer/mailer也被刪除,可以在 mymailer軟件包描述文件的%postun功能段內,加上刪除該文件的命令: %postun [ $1 = 0 ] && rm -f /etc/mymailer/maile 注: %postun段內為卸載後執行腳本程序,在mymailer包卸載後執行。 由上看出,當一個軟件包與另一個軟件包存在密切關系時,我們可以通過交互用功能段實現某些文件的管理,這不僅擴展了RPM軟件包管理的功能,又有助於軟件包的正常運行。 4. 其它功能段 其它功能段只有一個,即%changelog。這個段的內容是軟件維護記錄,它記錄每次軟件維護的時間,維護人及其EMAIL,維護的項目等。 %changelog段內容格式為: * 星期 月份 日子 年份 維護內容 注: 每個維護記錄均以*開頭,星期,月份均須為英文縮寫。維護內容多時可分行編寫, 每行開頭最好以減號(-)開頭。可以采用類似LZE方式的維護記錄寫作格式:(見LZE描述文件第80-85行)