玩轉rpm包製作

原文地址:一堂課玩轉rpm包的製作 作者:wjlkoorey258

常見的Linux發行版主要可以分爲兩類,類ReadHat系列和類Debian系列,這裏我們是以其軟件包的格式來劃分的,這兩類系統分別提供了自己的軟件包管理系統和相應的工具。類RedHat系統中軟件包的後綴是rpm;類Debian系統中軟件包的後綴是deb。另一方面,類RedHat系統提供了同名的rpm命令來安裝、卸載、升級rpm軟件包;類Debian系統同樣提供了dpkg命令來對後綴是deb的軟件包進行安裝、卸載和升級等操作。
   
rpm的全稱是Redhat Package Manager,常見的使用rpm軟件包的系統主要有FedoraCentOSopenSUSESUSE企業版、PCLinuxOS以及Mandriva LinuxMageia等。使用deb軟件包後綴的類Debian系統最常見的有DebianUbuntuFinnix等。

 

    無論是rpm命令還是dpkg命令在安裝軟件包時都存在一個讓人非常頭疼的問題,那就是軟件包的依賴關係。這一點很多人應該深有體會,這也使初學者在接觸Linux系統時覺得很不方便的地方。慶幸的是,很多發行版都考慮到了這問題,於是FedoraCentOS提供了yum來自動解決軟件包的安裝依賴,同樣的openSUSE提供了zypper,類Debian系統提供了apt-*命令。也就是說這些工具本質上最終還是調用了rpm(或者dpkg)是不過安裝前自動幫用戶解決了軟件包的安裝依賴。如下表所示:

分類發行版手動安裝命令自動安裝命令軟件包後綴
類RedHat
Fedora/CentOSrpm
yum*.rpm
openSUSE/SUSEzypper
Mandriva Linux/Mageiaurpmi
類DebianDebian/Ubuntudpkgapt-get*.deb

小技巧:執行rpmdev-setuptree會在當前用戶家目錄下的rpmbuild目錄(如果該目錄不存在也會被自動創建)裏自動建立上述目錄。
   
當上述目錄建立好之後,將所有用於生成rpm包的源代碼、shell腳本、配置文件都拷貝到SOURCES目錄裏,注意通常情況下源碼的壓縮格式都爲*.tar.gz格式(當然還可以爲其他格式,但那就是另外一種方式,這裏先不介紹)。然後,將最最最重要的SPEC文件,命名格式一般是“軟件名-版本.spec”的形式,將其拷貝到SPECS目錄下,切換到該目錄下執行:


  1. rpmbuild -bb 軟件名-版本.spec

    
   最終我們想要的
rpm軟件包就安安穩穩地躺在RPMS目錄下了。對,就這麼簡單。

   
這裏的關鍵就是上面的SPEC文件的寫法,我們可以用rpmdev-newspec -o Name-version.spec命令來生成SPEC文件的模板,然後在上面修改就可。例如:


  1. [root@localhost ~]# rpmdev-newspec -o myapp-0.1.0.spec

  2. Skeleton specfile (minimal) has been created to "myapp-0.1.0.spec".

  3. [root@localhost ~]# cat myapp-0.1.0.spec

  4. Name: myapp-0.1.0

  5. Version:

  6. Release: 1%{?dist}

  7. Summary:


  8. Group:

  9. License:

  10. URL:

  11. Source0:

  12. BuildRoot: %{_tmppath}/%{name}-%{version}-%{release}-root-%(%{__id_u} -n)


  13. BuildRequires:

  14. Requires:


  15. %description


  16. %prep

  17. %setup -q


  18. %build

  19. %configure

  20. make %{?_smp_mflags}


  21. %install

  22. rm -rf $RPM_BUILD_ROOT

  23. make install DESTDIR=$RPM_BUILD_ROOT


  24. %clean

  25. rm -rf $RPM_BUILD_ROOT


  26. %files

  27. %defattr(-,root,root,-)

  28. %doc


  29. %changelog


    其實
SPEC文件的核心是它定義了一些“階段”(%prep%build%install%clean),當rpmbuild執行時它首先會去解析SPEC文件,然後依次執行每個“階段”裏的指令。
   
接下來,我們來簡單瞭解一下SPEC文件的頭部。假如,我們的源碼包名字是myapp-0.1.0.tar.gz,那麼myapp-0.1.0.spec的頭部一般如下的樣子:


  1. Name:                  myapp <===軟件包的名字(後面會用到)

  2. Version:               0.1.0 <===軟件包的版本(後面會用到)

  3. Release:               1%{?dist} <===發佈序號

  4. Summary:               my first rpm <===軟件包的摘要信息


  5. Group:                 <===軟件包的安裝分類,參見/usr/share/doc/rpm-4.x.x/GROUPS這個文件

  6. License:               GPL <===軟件的授權方式

  7. URL:                   <===這裏本來寫源碼包的下載路徑或者自己的博客地址或者公司網址之類

  8. Source0:               %{name}-%{version}.tar.gz <===源代碼包的名稱(默認時rpmbuid回到SOURCES目錄中去找),這裏的name和version就是前兩行定義的值。如果有其他配 置或腳本則依次用Source1、Source2等等往後增加即可。


  9. BuildRoot:             %{_topdir}/BUILDROOT <=== 這是make install時使用的“虛擬”根目錄,最終制作rpm安裝包的文件就來自這裏。


  10. BuildRequires:         <=== 在本機編譯rpm包時需要的輔助工具,以逗號分隔。假如,要求編譯myapp時,gcc的版本至少爲4.4.2,則可以寫成gcc >=4.2.2。還有其他依賴的話則以逗號分別繼續寫道後面。

  11. Requires:              <=== 編譯好的rpm軟件在其他機器上安裝時,需要依賴的其他軟件包,也以逗號分隔,有版本需求的可以


  12. %description           <=== 軟件包的詳細說明信息,但最多只能有80個英文字符。


    下面我們來看一下製作
rpm包的幾個關鍵階段,以及所發生的事情:  

階段動作
%prep將%_sourcedir目錄下的源代碼解壓到%_builddir目錄下。如果有補丁的需要在這個階段進行打補丁的操作
%build在%_builddir目錄下執行源碼包的編譯。一般是執行./configure和make指令
%install將需要打包到rpm軟件包裏的文件從%_builddir下拷貝%_buildrootdir目錄下。當用戶最終用rpm -ivh name-version.rpm安裝軟件包時,這些文件會安裝到用戶系統中相應的目錄裏
製作rpm包這個階段是自動完成的,所以在SPEC文件裏面是看不到的,這個階段會%_buildroot目錄的相關文件製作成rpm軟件包最終放到%_rpmdir目錄裏
%clean編譯後的清理工作,這裏可以執行make clean以及清空%_buildroot目錄等

 

    每個階段的詳細說明如下:

  • %prep階段

    這個階段裏通常情況,主要完成對源代碼包的解壓和打補丁(如果有的話),而解壓時最常見到的就是一句指令:


  1. %setup -q


   當然,這句指令可以成功執行的前提是你位於
SOURCES目錄下的源碼包必須是name-version.tar.gz的格式才行,它還會完成後續階段目錄的切換和設置。如果在這個階段你不用這條指令,那麼後面每個階段都要自己手動去改變相應的目錄。解壓完成之後如果有補丁文件,也在這裏做。想了解的童鞋可以自己去查查如何實現,也不難,這裏我就不展開了。

  • %build階段

     這個階段就是執行常見的configuremake操作,如果有些軟件需要最先執行bootstrap之類的,可以放在configure之前來做。這個階段我們最常見只有兩條指令:


  1. %configure

  2. make %{?_smp_mflags}

    它就自動將軟件安裝時的路徑自動設置成如下約定:

  1. 可執行程序/usr/bin

  2. 依賴的動態庫/usr/lib或者/usr/lib64視操作系統版本而定。

  3. 二次開發的頭文件/usr/include

  4. 文檔及手冊/usr/share/man

   
    注意,這裏的
%configure是個宏常量,會自動將prefix設置成/usr。另外,這個宏還可以接受額外的參數,如果某些軟件有某些高級特性需要開啓,可以通過給%configure宏傳參數來開啓。如果不用 %configure這個宏的話,就需要完全手動指定configure時的配置參數了。同樣地,我們也可以給make傳遞額外的參數,例如:


  1. make %{?_smp_mflags} CFLAGS="" …


  • %install階段

    這個階段就是執行make install操作。這個階段會在%_buildrootdir目錄裏建好目錄結構,然後將需要打包到rpm軟件包裏的文件從%_builddir裏拷貝到%_buildrootdir裏對應的目錄裏。這個階段最常見的兩條指令是:


  1. rm -rf $RPM_BUILD_ROOT

  2. make install DESTDIR=$RPM_BUILD_ROOT


   其中
$RPM_BUILD_ROOT也可以換成我們前面定義的BuildRoot變量,不過要寫成%{buildroot}纔可以,必須全部用小寫,不然要報錯。
   
如果軟件有配置文件或者額外的啓動腳本之類,就要手動用copy命令或者install命令你給將它也拷貝到%{buildroot}相應的目錄裏。用copy命令時如果目錄不存在要手動建立,不然也會報錯,所以推薦用install命令。 


  • %clean階段

    編譯完成後一些清理工作,主要包括對%{buildroot}目錄的清空(當然這不是必須的),通常執行諸如make clean之類的命令。 


  • 製作rpm軟件包的階段

    這個階段必須引出下面一個叫做%files的階段。它主要用來說明會將%{buildroot}目錄下的哪些文件和目錄最終打包到rpm包裏。


  1. %files

  2. %defattr(-,root,root,-)

  3. %doc

    
   在
%files階段的第一條命令的語法是:


  1. %defattr(文件權限,用戶名,組名,目錄權限)


   如果不牽扯到文件、目錄權限的改變則一般用%defattr(-,root,root,-)這條指令來爲其設置缺省權限。所有需要打包到rpm包的文件和目錄都在這個地方列出,例如:


  1. %files

  2. %{_bindir}/*

  3. %{_libdir}/*

  4. %config(noreplace) %{_sysconfdir}/*.conf


   在安裝
rpm時,會將可執行的二進制文件放在/usr/bin目錄下,動態庫放在/usr/lib或者/usr/lib64目錄下,配置文件放在/etc目錄下,並且多次安裝時新的配置文件不會覆蓋以前已經存在的同名配置文件。
   
這裏在寫要打包的文件列表時,既可以以宏常量開頭,也可以爲“/”開頭,沒任何本質的區別, 都表示從%{buildroot}中拷貝文件到最終的rpm包裏;如果是相對路徑,則表示要拷貝的文件位於%{_builddir}目錄,這主要適用於那 些在%install階段沒有被拷貝到%{buildroot}目錄裏的文件,最常見的就是諸如README、LICENSE之類的文件。如果不想將% {buildroot}裏的某些文件或目錄打包到rpm裏,則用:


  1. %exclude dic_name或者file_name

    
   但是關於
%files階段有兩個特性要牢記:

  1. %{buildroot}裏的所有文件都要明確被指定是否要被打包到rpm裏。什麼意思呢?假如,%{buildroot}目錄下有4個目錄abcd,在%files裏僅指定ab要打包到rpm裏,如果不把cdexclude聲明是要報錯的;

  2. 如果聲明瞭%{buildroot}裏不存在的文件或者目錄也會報錯。

    關於%doc宏,所有跟在這個宏後面的文件都來自%{_builddir}目錄,當用戶安裝rpm時,由這個宏所指定的文件都會安裝到/usr/share/doc/name-version/目錄裏。
 

  • %changelog階段

    這是最後一個階段,主要記錄的每次打包時的修改變更日誌。標準格式是:


  1. * date +"%a %b %d %Y" 修改人 郵箱 本次版本x.y.z-p

  2. - 本次變更修改了那些內容

    
   說了這麼多,我們實戰一下。網上很多教程都是拿
Tomcat或者Nigix開頭,這裏我就先從簡單的mp3解碼庫libmad入手,將它打成一個rpm包,具體步驟如下:

    (如果自己系統上沒有rpmbuild命令就安裝之:yum install rpm* rpm-build rpmdev*)

    1、構建rpm的編譯目錄結構:

   2、下載libmad源碼到rpmbuild/SOURCES目錄下,可以從 http://downloads.sourceforge.net/mad/libmad-0.15.1b.tar.gz這裏下載。

    3、在rpmbuild/SPECS目錄下執行rpmdev-newspec -o libmad-0.15.1b.spec,會在當前目錄下生成名爲libmad-0.15.1b.spec的模板文件。

    4、將libmad-0.15.1b.spec修改成如下的樣子:

    5、在rpmbuild/SPECS目錄下執行打包編譯:


  1. rpmbuild -bb libmad-0.15.1b.spec


    最終生成的rpm包如下:

    因爲我是64位系統,所以編譯出的libmad適用於CentOS6.0-64

    如果我們將libmad的源碼和spec文件拷貝32位系統上,再執行rpm打包,看看結果:
    結果如下:

後記:
   關於SPEC文件,還有一些其他特性,諸如安裝軟件包之前、之後要做的事情,以及卸載軟件包之前之後要做的事情,包括給源碼打補丁,關於這些特性感興趣的童鞋自己去摸索吧。最後給出一個完整的,包含了打補丁、安裝、卸載特性的SPEC文件模板:


  1. Name: test

  2. Version:

  3. Requires:

  4. %description

  5. #==================================SPEC頭部====================================

  6. %prep

  7. %setup -q

  8. %patch <==== 在這裏打包


  9. %build

  10. %configure

  11. make %{?_smp_mflags}


  12. %install

  13. rm -rf $RPM_BUILD_ROOT

  14. make install DESTDIR=$RPM_BUILD_ROOT


  15. %clean

  16. rm -rf $RPM_BUILD_ROOT


  17. %files

  18. %defattr(-,root,root,-)

  19. 要打包到rpm包裏的文件清單

  20. %doc

  21. %changelog

  22. #==================================SPEC主體====================================


  23. %pre

  24. 安裝或者升級軟件前要做的事情,比如停止服務、備份相關文件等都在這裏做。

  25. %post

  26. 安裝或者升級完成後要做的事情,比如執行ldconfig重構動態庫緩存、啓動服務等。

  27. %preun

  28. 卸載軟件前要做的事情,比如停止相關服務、關閉進程等。

  29. %postun

  30. 卸載軟件之後要做的事情,比如刪除備份、配置文件等。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章