一、軟件包製作
1,描述文件
製作rpm軟件包的關鍵,就是編寫用於生成軟件包的spec文件(描述文件)。該文件描述了製作軟件包時候所需的信息。下面介紹製作rpm包所需的spec文件的相關內容。
首先,要在製做rpm包之前,建立好一些必要的目錄結構,例如BUILD,SOURCES,等,然後rpm的相關工具會將這些目錄的父目錄以%{_topdir}表示,這個%{_topdir}默認值爲系統中的某個目錄,例如"usr/local/redhat"等,如果使用自己的目錄,需要自行修改這個變量,後面的例子中會有所說明。
spec腳本的主體中也包括了很多關鍵字,描述內容主要包含文件頭以及各個段,主要的段包括:%prep段,%build段 ,%install段,%files段 ,%changelog段等,每個段大致代表一個處理階段,下面依次介紹。更具體的信息,可以參見/usr/share/doc/rpm-<version>中的文檔以及後面的參考資料。
1、文件頭
文件頭內容主要如下:
Name:軟件包的名稱,後面可使用%{name}的方式引用
Summary:軟件包的內容概要
Version:軟件的實際版本號,例如:1.0.1等,後面可使用%{version}引用
Release:發佈序列號,例如:1linuxing等,標明第幾次打包,後面可使用%{release}引用
Group:軟件分組,建議使用標準分組
License:軟件授權方式,通常就是GPL
Source:源代碼包,可以帶多個用Source1、Source2等源,後面也可以用%{source1}、%{source2}引用
-
BuildRoot:這個是安裝或編譯時使用的“虛擬目錄”。
考慮到多用戶的環境,一般定義爲:
%{_tmppath}/%{name}-%{version}-%{release}-root或%{_tmppath}/%{name}-%{version}-%{release}-buildroot-%(%{__id_u} -n}
該參數非常重要,因爲在生成rpm的過程中,執行make install時就會把軟件安裝到上述的路徑中,在打包的時候,同樣依賴“虛擬目錄”爲“根目錄”進行操作。後面可使用$RPM_BUILD_ROOT 方式引用。
URL:軟件的主頁
Vendor:發行商或打包組織的信息,例如RedFlag Co,Ltd
Disstribution:發行版標識
Patch:補丁源碼,可使用Patch1、Patch2等標識多個補丁,使用%patch0或%{patch0}引用
Prefix:%{_prefix} 這個主要是爲了解決今後安裝rpm包時,並不一定把軟件安裝到rpm中打包的目錄的情況。這樣,必須在這裏定義該標識,並在編寫%install腳本的時候引用,才能實現rpm安裝時重新指定位置的功能
Prefix:%{_sysconfdir} 這個原因和上面的一樣,但由於%{_prefix}指/usr,而對於其他的文件,例如/etc下的配置文件,則需要用%{_sysconfdir}標識
Build Arch:指編譯的目標處理器架構,noarch標識不指定,但通常都是以/usr/lib/rpm/marcros中的內容爲默認值
-
Requires:該rpm包所依賴的軟件包名稱。
可以用>=或<=表示大於或小於某一特定版本,例如:
libpng-devel >= 1.0.20 zlib
這裏,“>=”號兩邊需用空格隔開,而不同軟件名稱也用空格分開
還有例如PreReq、Requires(pre)、Requires(post)、Requires(preun)、Requires(postun)、BuildRequires等都是針對不同階段的依賴指定
Provides:指明本軟件一些特定的功能,以便其他rpm識別
Packager:打包者的信息
%description 軟件的詳細說明
2、文件段
%prep段
包含預處理腳本,通常用來執行一些解開源程序包的命令,爲下一步的編譯安裝作準備(一般來說,都是從SOURCES目錄中將源代碼解壓到BUILD中)。腳本運行的當前目錄在BUILD中。
%prep和下面%build,%install段一樣,除了可以執行RPM所定義的宏命令(以%開頭)以外,還可以執行SHELL命令,命令可以有很多行。
-
%setup -n %{name}-%{version} 把源碼包解壓並放好
通常從%{_topdir}/SOURCES裏的包解壓到%{_topdir}/BUILD/%{name}-%{version}中。
一般用%setup -c就可以了,但有兩種情況:一就是同時編譯多個源碼包,二就是源碼的tar包的名稱與解壓出來的目錄不一致,此時,就需要使用-n參數指定一下了。
對於%setup,具體還包含如下選項:
- %setup 不加任何選項,僅將軟件包打開。
- %setup -n newdir 將軟件包解壓在newdir目錄。
- %setup -c 解壓縮之前先產生目錄。
- %setup -b num 將第num個source文件解壓縮。
- %setup -T 不使用default的解壓縮操作。
- %setup -T -b 0 將第0個源代碼文件解壓縮。
- %setup -c -n newdir 指定目錄名稱newdir,並在此目錄產生rpm套件。
- %patch 最簡單的補丁方式,自動指定patch level。
- %patch 0 使用第0個補丁文件,相當於%patch ?p 0。
- %patch -s 不顯示打補丁時的信息。
- %patch -T 將所有打補丁時產生的輸出文件刪除。
-
%patch 打補丁
通常補丁都會一起在源碼tar.gz包中,或放到SOURCES目錄下。一般參數爲:
- %patch -p1 使用前面定義的Patch補丁進行,-p1是忽略patch的第一層目錄
- %Patch2 -p1 -b xxx.patch 打上指定的補丁,-b是指生成備份文件
-
%configure
這個不是關鍵字,而是rpm定義的標準宏命令。意思是執行源代碼的configure配置
在%{_topdir}/BUILD/%{name}-%{version}目錄中進行 ,使用標準寫法,會引用/usr/lib/rpm/marcros中定義的參數。
另一種不標準的寫法是,可參考源碼中的參數自定義,例如:
CFLAGS="$RPM_OPT_FLAGS" CXXFLAGS="$RPM_OPT_FLAGS" ./configure --prefix=%{_prefix}
%build段
包含爲生成軟件包服務所執行的命令,通常是編譯生成可執行文件。生成的可執行文件在install中會用到。腳本運行的當前目錄在BUILD中。
相當於在%{_topdir}/BUILD/%{name}-%{version}目錄中進行make的工作 ,常見寫法如:make %{?_smp_mflags} OPTIMIZE="%{optflags}"都是一些優化參數,定義在/usr/lib/rpm/marcros。
%install段
包含把軟件安裝到虛擬的根目錄中的命令。這裏的虛擬根目錄就是一個子目錄,其目錄結構和根目錄一樣,%install會把最終安裝好的軟件的目錄結構反應到這個虛擬根目錄中。然後根據這個虛擬根目錄和後面的%files段內容,將軟件製作成rpm包。其當前工作目錄也是BUILD。它一般會在%{_topdir}/BUILD/%{name}-%{version}目錄中進行make install的操作。這個很重要,因爲如果這裏的路徑不對的話,則下面%file中尋找文件的時候就會失敗。 常見內容有:
%makeinstall
這不是關鍵字,而是rpm定義的標準宏命令。也可以使用非標準寫法:
make DESTDIR=$RPM_BUILD_ROOT install
make prefix=$RPM_BUILD_ROOT install
需要說明的是,這裏的%install主要就是爲了後面的%file服務的。所以,還可以使用常規的系統命令:
install -d $RPM_BUILD_ROOT/
cp -a * $RPM_BUILD_ROOT/
總之,這裏是製作rpm包,並不是安裝軟件,所以只是將文件安裝到虛擬根目錄中,千萬要指定好了虛擬根目錄,否則就真的安裝到真實的系統中了,向虛擬根目錄中安裝好了之後,再利用虛擬根目錄製作rpm包,而安裝rpm包的時候,才真正將軟件安裝到你的系統上。
%clean段
這個段用來清理臨時文件,在製作好了rpm包之後,執行這個段中的內容,清除製作過程中產生的中間文件。例如BUILD中的,以及虛擬根目錄中的內容。
通常內容爲:
[ "$RPM_BUILD_ROOT" != "/" ] && rm -rf "$RPM_BUILD_ROOT"
rm -rf $RPM_BUILD_DIR/%{name}-%{version}
這裏注意:對於RPM_BUILD_DIR:
- RPM_BUILD_DIR通常就是指%{_topdir}/BUILD,其中,前面的纔是%file需要的。
- %pre rpm安裝前執行的腳本
- %post rpm安裝後執行的腳本
- %preun rpm卸載前執行的腳本
- %postun rpm卸載後執行的腳本
- %preun %postun 的區別是什麼呢?
前者在升級的時候會執行,後者在升級rpm包的時候不會執行。
%files段
定義哪些文件或目錄會放入rpm中,rpm安裝會安裝哪些文件。
用於定義軟件包所包含的文件,分爲三類–說明文檔(doc),配置文件(config)及執行程序,還可定義文件存取權限,擁有者及組別。
這裏所指定的文件路徑,是相對於虛擬根目錄下的文件路徑,千萬不要寫絕對路徑,而應用宏或變量表示相對路徑。 如果描述爲目錄,表示目錄中除%exclude外的所有文件。
- %defattr (-,root,root) 指定包裝文件的屬性,分別是(mode,owner,group),-表示默認值,對文本文件是0644,可執行文件是0755。
- %exclude 列出不想打包到rpm中的文件。這裏注意,如果%exclude指定的文件不存在,也會出錯的。
%changelog段
本段是修改日誌段。你可以將軟件的每次修改記錄到這裏,保存到發佈的軟件包中,以便查詢之用。
每一個修改日誌都有這樣一種格式:
- 第一行是:
* 星期 月 日 年 修改人 電子信箱
。其中:星期、月份均用英文形式,用中文會出錯。 - 接下來的行寫的應是修改了什麼地方,可寫多行。一般以減號起始,便於查閱。
一些rpm相關雜亂信息
-
以上各個段中,比較容易混淆的就是目錄,我們需要記住兩點:
-
%build和%install中,都必須把編譯和安裝的文件定義到“虛擬根目錄” 中。
例如:
%build 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/
-
%file中用的是相對目錄
例如:
%files %defattr(-,root,root) %{_bindir} 如果寫成: %files %defattr(-,root,root) /usr/bin
則打包的會是根目錄下的/usr/bin中所有的文件,而不是本軟件中的文件了。
- rpm軟件包系統的標準分組:/usr/share/doc/rpm-4.3.3/GROUPS
- 各種宏定義: /usr/lib/rpm/macros
- 已經安裝的rpm包數據庫: /var/lib/rpm
如果要避免生成debuginfo包:這個是默認會生成的rpm包。則可以使用下面的命令:
$echo '%debug_package %{nil}' >> ~/.rpmmacros
由於必須在%file中包括所有套件中的文件,所以,我們需要清楚編譯完的套件到底包括那些文件
常見的做法是,人工模擬一次編譯的過程:
$./configrue --prefix=/usr/local/xxx $make $make DESTDIR=/usr/local/xxx install
或
$make prefix=/usr/local/xxx install
這樣,整個套件的內容就會被放到/usr/local/xxx中,可根據情況編寫%file和%exclude段(當然,這個只能對源碼按GNU方式編寫,並使用GNU autotool創建的包有效,若自定義Makefile則不能一概而論)。
-
-
關於rpm中的執行腳本
如果正在製作的rpm包是準備作爲放到系統安裝光盤中的話,則需要考慮rpm中定義的腳本是否有問題。
由於系統在安裝的時候只是依賴於一個小環境進行,而該環境與實際安裝完的環境有很大的區別,所以,大部分的腳本在該安裝環境中都是無法生效,甚至會帶來麻煩的。
所以,對於這樣的,需要放到安裝光盤中的套件,不加入執行腳本是較佳的方法。
-
信號機制
爲提供操作中可參考的信息,rpm還提供了一種信號機制:不同的操作會返回不同的信息,並放到默認變量$1中。對於信號值,0代表卸載、1代表安裝、2代表升級。
例如可這樣使用:
%postun if [ "$1" = "0" ]; then /sbin/ldconfig fi
-
下面是宏對應路徑一覽表
-
一些模仿autoconf的變量
- %{_sysconfdir} /etc
- %{_prefix} /usr
- %{_exec_prefix} %{_prefix}
- %{_bindir} %{_exec_prefix}/bin
- %{_lib} lib (lib64 on 64bit systems)
- %{_libdir} %{_exec_prefix}/%{_lib}
- %{_libexecdir} %{_exec_prefix}/libexec
- %{_sbindir} %{_exec_prefix}/sbin
- %{_sharedstatedir} /var/lib
- %{_datadir} %{_prefix}/share
- %{_includedir} %{_prefix}/include
- %{_oldincludedir} /usr/include
- %{_infodir} /usr/share/info
- %{_mandir} /usr/share/man
- %{_localstatedir} /var
- %{_initddir} %{_sysconfdir}/rc.d/init.d
注意:比Fedora10早的版本(或EPEL)中,%{_initddir}沒有。這時候可以使用舊的%{_initrddir}宏。
-
RPM目錄的宏
- %{_topdir} %{getenv:HOME}/rpmbuild
- %{_builddir} %{_topdir}/BUILD
- %{_rpmdir} %{_topdir}/RPMS
- %{_sourcedir} %{_topdir}/SOURCES
- %{_specdir} %{_topdir}/SPECS
- %{_srcrpmdir} %{_topdir}/SRPMS
- %{_buildrootdir} %{_topdir}/BUILDROOT
注意:比Fedora10早的版本(或EPEL)中, %{_buildrootdir} 沒有。
-
編譯編輯宏
- %{_global_cflags} -O2 -g -pipe
- %{_optflags} %{__global_cflags} -m32 -march=i386 -mtune=pentium4 # if redhat-rpm-config is installed
-
其它宏
- %{_var} /var
- %{_tmppath} %{_var}/tmp
- %{_usr} /usr
- %{_usrsrc} %{_usr}/src
- %{_docdir} %{_datadir}/doc
-
-
一個帶有註釋的較爲完整的spec文件的例子
#+++++++++以下是文件內容+++++++++++# ######頭部###### Summary:一個簡單的打印hello的程序 Name:myapplication Version:1.0 Release:1 Vendor:QuietHeart ([email protected]) License:Share SOURCE:%{name}-%{version}.tgz BuildRoot:%{_tmppath}/%{name}-%{version}-%{release}-root Group:Applications/Editors URL:quietheart.sf.net Prefix:%{_prefix} Prefix:%{_sysconfdir} Prefix:%{_datadir} Packager:QuietHeart %define myconfig myconfig.conf %define mylib libmy.so %description 描述省略。 ######prep,build,install三個段都可以執行shell命令###### # 預處理段,爲下一步的編譯安裝作準備。例如將源代碼拷貝到BUILDS目錄。 %prep # prep start. echo "======>In :prep section $(pwd)" echo "======>In :prep section " %{_topdir} echo "======>In :prep section $RPM_BUILD_ROOT" echo "======>In :prep section " %{_sourcedir} #echo "======>In :prep section $RPM_SOURCE_DIR" #將源代碼包解壓並放好,也可以使用tar命令,解壓好的目錄:%{name}-%{version},存在BUILD中。 %setup -n %{name}-%{version} #tar -xzvf %{_sourcedir}/%{name}-%{version}.tgz -C %{_builddir} # 建立段,執行一些編譯命令以便生成軟件包。工作於BUILDS。 %build # build start. echo "======>In :build section $(pwd)" echo "======>In :build section " %{_topdir} echo "======>In :build section $RPM_BUILD_ROOT" echo "======>In :build section " %{_builddir} #echo "======>In :build section $RPM_BUILD_DIR" #自動進入myapplication-1.0中了。 make # 安裝段,在安裝軟件包階段執行的命令。 # 安裝的內容安裝到“虛擬根目錄中”install是爲了後面的file段服務的。 %install # install start. echo "======>In :install section $(pwd)" echo "======>In :install section " %{_topdir} echo "======>In :install section $RPM_BUILD_ROOT" mkdir -p $RPM_BUILD_ROOT/usr/bin mkdir -p $RPM_BUILD_ROOT/usr/lib mkdir -p $RPM_BUILD_ROOT/etc #這裏使用%{name}表示開始定義的Name,即myapplication。 cp %{name} $RPM_BUILD_ROOT/usr/bin cp lib/%{mylib} $RPM_BUILD_ROOT/usr/lib cp %{myconfig} $RPM_BUILD_ROOT/etc ######其它的一些段###### %clean # clean start. echo "======>In :clean section $(pwd)" #文件段,定義軟件包所包含的文件。具體可由後面"%defattr","%doc","%config"宏定義。 #主要包含:config(配置文件),doc(文檔文件),bin(二進制文件) %files #定義文件屬性:%defattr(權限,屬主,屬組)。其中權限'-'表默認,可用'0777'形式。 %defattr (-,root,root) #定義製作軟件包包含的文檔文件,每個宏定義一個,可指定絕對路徑。 #一般文檔文件會被安裝到"/usr/doc/Name-Version-Release"目錄下。 %doc README %doc COPYRIGHT #定義軟件包所需要的配置文件(還是安裝的配置文件位置??) #當卸載軟件的時候會將沒有修改過的卸掉,修改過的備份爲<name>.rpmsave。 %config %{_sysconfdir}/%{myconfig} #軟件包所包含的二進制文件,可以爲目錄 %{_bindir}/%{name} %{_libdir}/%{mylib} #修改日誌段,可以記錄每次的修改日誌。 #第一行是:* 星期 月 日 年 修改人 電子信箱。 #其中:星期、月份均用英文形式,用中文會出錯。 #接下來的行寫的應是修改了什麼地方,可寫多行。一般以減號起始,便於查閱。 #修改的時候,新的必須在上面。 %changelog *Fri Sep 30 2011 QuietHeart - 增加XXX內容2 *Fri Sep 29 2011 QuietHeart - 增加XXX內容1 #+++++++++以下是文件內容+++++++++++#
2,製做rpm包的具體方法
2.1,工具
通過rpmbuild可以生成相應的軟件包,下面介紹這個工具的使用,以及幾個完整的製作rpm軟件包的例子。更多使用這個工具的信息,參見"man rpmbuild"。
rpmbuild {-ba|-bb|-bp|-bc|-bi|-bl|-bs} [rpmbuild-options] SPECFILE ...
rpmbuild {-ta|-tb|-tp|-tc|-ti|-tl|-ts} [rpmbuild-options] TARBALL ...
rpmbuild {--rebuild|--recompile} SOURCEPKG ...
功能
創建rpm軟件包。
描述
rpmbuild可以用來製作二進制或者源碼軟件包。軟件包包含文件以及一些meta-data,可以用來安裝或者卸載軟件之用。mata-data包含幫助腳本,文件屬性以及軟件包的其他描述信息。軟件包有兩種形式:二進制軟件包,用來安裝軟件時候使用(一般就是將已經編譯好可以直接運行的程序打包而成);源碼軟件包,包含源代碼等可以構建二進制軟件包的文件。
這個工具有三種必選的基本模式:Build Package, Build Package from Tarball, Recompile Package, Show Configuration.這裏重點介紹第一種,也就是構建軟件包(rpm包)的模式。
-
通用選項
以下是各種模式下都可以使用的通用選項:
- -?, –help: 打印幫助信息。
- –version: 打印單行的,被使用的rpm的版本信息。
- –quiet: 打印儘可能少的信息,通常只包含錯誤信息。
- -v: 打印詳細信息,一般都包含處理過程。
- -vv: 打印儘可能多的信息。
- –rcfile FILELIST: 依次讀取FILELIST中被":"分割的文件用於配置信息。第一個文件必須存在,默認FILELIST是:"usr/lib/rpm/rpmrc:/usr/lib/rpm/redhat/rpmrc:/etc/rpmrc:~.rpmrc".
- –pipe CMD: 將輸出通過管道輸送給CMD命令。
- –dbpath DIRECTORY: 使用DIRECTORY中的數據庫,而不是默認的"var/lib/rpm"中的數據庫。
- –root DIRECTORY: 使用DIRECTORY做爲所有操作的相對的文件系統根目錄。注意這也意味着chroot到DIRECTORY之後,DIRECTORY中的數據庫被用來做依賴性的檢查以及運行一些腳本片段(例如:安裝時候的%post,或者編譯時候的%prep)。
-
BUILD模式的選項
rpm的build命令一般形式爲:
rpmbuild -bSTAGE|-tSTAGE [ rpmbuild-options ] FILE ...
如果使用spec文件進行構建,那麼使用的爲-b參數,如果使用tar文件中的spec文件進行構建,那麼使用-t的參數。-b或者-t參數之後的STAGE參數指定了執行構建軟件包中的哪個階段(對應於spec文件中的預處理,構建,安裝等各個階段)。
- -ba: 構建二進制和源代碼包(執行完spec文件中的%prep,%build,和%install階段之後做)。
- -bb: 構建二進制包(執行完spec文件中的%prep,%build,和%install階段之後做)。
- -bp: 執行spec文件中的"%prep"段中的內容。這個段一般都是用來解壓準備生成將要編譯的源代碼以及應用補丁等時候用的。
- -bc: 執行spec文件中的"%build"段中的內容(先運行%prep段之後運行)。這個段一般就是相當於進入源代碼中,執行"make",生成可以安裝甚至執行的二進制文件。
- -bi: 執行spec文件中的"%install"段中的內容(先運行%prep,%build段之後運行)。這個段一般就是相當於進入源代碼中,執行"make install",將生成的二進制等文件安裝到一個虛擬的根目錄中(就是將那個目錄當做根目錄來看待,那個目錄中有usr,etc等根目錄中相同的結構),以便後面打包時候使用,以後安裝的時候,一般就按照虛擬根目錄中的結構將軟件安裝。
- -bl: 進行文件列表檢查,spec文件的"%files"段是一個宏擴展,這個檢查用來確保每個文件是存在的。
- -bs: 只構建生成源碼軟件包。
下面是一些build模式中的額外選項:
- –buildroot DIRECTORY: 構建軟件包的時候,將spec文件中的BuildRoot路徑用DIRECTORY來替代(就是指定DIRECTORY爲虛擬根目錄)。
- –clean: 製作好軟件包之後,清除編譯目錄。如果不指定,那麼構建好軟件包之後,BUILD下還有解壓的軟件源代碼以及編譯中間文件。
- –nobuild: 不執行任何編譯階段的內容,用於測試spec文件。
- –rmsource: 構建之後,刪除源碼(可以單獨使用,例如 "rpmbuild –rmsource foo.spec")。
- –rmspec: 構建之後,刪除spec文件(可以單獨使用,例如 "rpmbuild –rmspec foo.spec")。
另外,命令: "rpmbuild –showrc" 可以顯示rpmbuild將要使用的當前rpmrc中設置的所有選項和宏值。
2.2,舉例
一個簡單的測試
這裏,對於rpmbuild命令,假設建立一個簡單的spec文件myapplication.rpm.spec,然後對它的各種命令選項進行測試。
-
1)進行之前,查看當前路徑以及文件如下
# pwd /root/test/rpm_test/BUILD # ls Copyright libmy.so myapplication myapplication.rpm.spec myconfig1.conf myconfig2.conf README
-
2)查看myapplication.rpm.spec文件如下
#cat myapplication.rpm.spec #+++++++++以下是文件內容+++++++++++# ######頭部###### Summary:一個簡單的打印hello的程序 Name:myapplication Version:1.0 Release:1 Vendor:QuietHeart ([email protected]) License:Share BuildRoot:%{_tmppath}/%{name}-%{version}-%{release}-root Group:Applications/Editors URL:quietheart.sf.net Prefix:%{_prefix} Prefix:%{_sysconfdir} Prefix:%{_datadir} Packager:QuietHeart %description 描述省略。 ######prep,build,install三個段都可以執行shell命令###### # 預處理段,爲下一步的編譯安裝作準備。例如將源代碼拷貝到BUILDS目錄。 %prep # prep start. echo "======>In :prep section $(pwd)" #echo "======>In :prep section " %{_topdir} #echo "======>In :prep section $RPM_BUILD_ROOT" #echo "======>In :prep section " %{_sourcedir} #echo "======>In :prep section $RPM_SOURCE_DIR" # 建立段,執行一些編譯命令以便生成軟件包。工作於BUILDS。 %build # build start. echo "======>In :build section $(pwd)" #echo "======>In :build section " %{_topdir} #echo "======>In :build section $RPM_BUILD_ROOT" #echo "======>In :build section " %{_builddir} #echo "======>In :build section $RPM_BUILD_DIR" # 安裝段,在安裝軟件包階段執行的命令。 # 安裝的內容安裝到“虛擬根目錄中”install是爲了後面的file段服務的。 %install # install start. echo "======>In :install section $(pwd)" #echo "======>In :install section " %{_topdir} #echo "======>In :install section $RPM_BUILD_ROOT" ######其它的一些段###### #文件段,定義軟件包所包含的文件。具體可由後面"%defattr","%doc","%config"宏定義。 #主要包含:config(配置文件),doc(文檔文件),bin(二進制文件) %files #定義文件屬性:%defattr(權限,屬主,屬組)。其中權限'-'表默認,可用'0777'形式。 %defattr (-,root,root) #定義製作軟件包包含的文檔文件,每個宏定義一個,可指定絕對路徑。 #一般文檔文件會被安裝到"/usr/doc/Name-Version-Release"目錄下。 %doc README %doc Copyright #定義軟件包所需要的配置文件(還是安裝的配置文件位置??) #當卸載軟件的時候會將沒有修改過的卸掉,修改過的備份爲<name>.rpmsave。 %config %{_sysconfdir}/myconfig1.conf %config %{_sysconfdir}/myconfig2.conf #軟件包所包含的二進制文件,可以爲目錄 #%{_bindir}/myapplication #%{_libdir}/libmy.so #修改日誌段,可以記錄每次的修改日誌。 #第一行是:* 星期 月 日 年 修改人 電子信箱。 #其中:星期、月份均用英文形式,用中文會出錯。 #接下來的行寫的應是修改了什麼地方,可寫多行。一般以減號起始,便於查閱。 #修改的時候,新的必須在上面。 %changelog *Fri Sep 30 2011 QuietHeart - 增加XXX內容2 *Fri Sep 29 2011 QuietHeart - 增加XXX內容1 #+++++++++以上是文件內容+++++++++++#
-
3)依次測試常用的rpmbuild命令如下
-
執行myapplication.rpm.spec文件中的prep段
#rpmbuild -bp myapplication.rpm.spec
輸入之後,輸出如下:
Executing(%prep): /bin/sh -e /var/tmp/rpm-tmp.23258 + umask 022 + cd /usr/src/redhat/BUILD + LANG=C + export LANG + unset DISPLAY ++ pwd + echo '======>In :prep section /usr/src/redhat/BUILD' ======>In :prep section /usr/src/redhat/BUILD + exit 0
這裏,prep段是編譯之前的預處理段,一般都用做將一些類似源代碼文件等拷貝到合適的位置,有待編譯。由此可知,處理prep的時候,自動將當前路徑切換到了"/usr/src/redhat/BUILD"中。
-
執行myapplication.rpm.spec文件中的build段
#rpmbuild -bc myapplication.rpm.spec
輸入之後,輸出如下:
Executing(%prep): /bin/sh -e /var/tmp/rpm-tmp.36144 + umask 022 + cd /usr/src/redhat/BUILD + LANG=C + export LANG + unset DISPLAY ++ pwd + echo '======>In :prep section /usr/src/redhat/BUILD' ======>In :prep section /usr/src/redhat/BUILD + exit 0 Executing(%build): /bin/sh -e /var/tmp/rpm-tmp.36144 + umask 022 + cd /usr/src/redhat/BUILD + LANG=C + export LANG + unset DISPLAY ++ pwd + echo '======>In :build section /usr/src/redhat/BUILD' ======>In :build section /usr/src/redhat/BUILD + exit 0
這裏,build段一般都是執行源代碼編譯的動作。由這裏可見,執行build段之前會先執行prep段。處理build的時候,自動將當前路徑切換到了"/usr/src/redhat/BUILD"中。
-
執行myapplication.rpm.spec文件中的install段
#rpmbuild -bi myapplication.rpm.spec
輸入之後,輸出如下:
Executing(%prep): /bin/sh -e /var/tmp/rpm-tmp.27835 + umask 022 + cd /usr/src/redhat/BUILD + LANG=C + export LANG + unset DISPLAY ++ pwd + echo '======>In :prep section /usr/src/redhat/BUILD' ======>In :prep section /usr/src/redhat/BUILD + exit 0 Executing(%build): /bin/sh -e /var/tmp/rpm-tmp.27835 + umask 022 + cd /usr/src/redhat/BUILD + LANG=C + export LANG + unset DISPLAY ++ pwd + echo '======>In :build section /usr/src/redhat/BUILD' ======>In :build section /usr/src/redhat/BUILD + exit 0 Executing(%install): /bin/sh -e /var/tmp/rpm-tmp.27835 + umask 022 + cd /usr/src/redhat/BUILD + LANG=C + export LANG + unset DISPLAY ++ pwd + echo '======>In :install section /usr/src/redhat/BUILD' ======>In :install section /usr/src/redhat/BUILD + /usr/lib/rpm/redhat/brp-compress + /usr/lib/rpm/redhat/brp-strip /usr/bin/strip + /usr/lib/rpm/redhat/brp-strip-static-archive /usr/bin/strip + /usr/lib/rpm/redhat/brp-strip-comment-note /usr/bin/strip /usr/bin/objdump + /usr/lib/rpm/brp-python-bytecompile + /usr/lib/rpm/redhat/brp-java-repack-jars Processing files: myapplication-1.0-1 error: File not found: /var/tmp/myapplication-1.0-1-root/etc/myconfig1.conf error: File not found: /var/tmp/myapplication-1.0-1-root/etc/myconfig2.conf Executing(%doc): /bin/sh -e /var/tmp/rpm-tmp.88394 + umask 022 + cd /usr/src/redhat/BUILD + DOCDIR=/var/tmp/myapplication-1.0-1-root/usr/share/doc/myapplication-1.0 + export DOCDIR + rm -rf /var/tmp/myapplication-1.0-1-root/usr/share/doc/myapplication-1.0 + /bin/mkdir -p /var/tmp/myapplication-1.0-1-root/usr/share/doc/myapplication-1.0 + cp -pr README /var/tmp/myapplication-1.0-1-root/usr/share/doc/myapplication-1.0 cp: 無法 stat “README”: 沒有那個文件或目錄 error: Bad exit status from /var/tmp/rpm-tmp.88394 (%doc) Checking for unpackaged file(s): /usr/lib/rpm/check-files /var/tmp/myapplication-1.0-1-root RPM build errors: File not found: /var/tmp/myapplication-1.0-1-root/etc/myconfig1.conf File not found: /var/tmp/myapplication-1.0-1-root/etc/myconfig2.conf Bad exit status from /var/tmp/rpm-tmp.88394 (%doc)
這裏,由於install段沒有建立相應的文件,出現了錯誤,但是根據錯誤的提示,我們還是可以知道究竟rpmbuild做了什麼的。
install段主要就是爲了後面指定的file段服務的,也就是說install段將需要安裝的文件安裝到虛擬根目錄中,然後file段指定被安裝到虛擬根目錄中的文件。從這裏看出,install沒有做任何的動作,並且執行install段的時候已經執行了prep段和build段,同時當前路徑爲'/usr/src/redhat/BUILD',然後就將install段執行完了。接着,將自動執行file段,根據file段指示的文件以及之前在install段拷貝好的一些文件,以及虛擬根目錄myapplication.rpm.spec中的"BuildRoot:%{_tmppath}/%{name}-%{version}-%{release}-root"指定的路徑,執行一些動作。另外實踐發現,這裏使用"rpmbuild -ba myapplication.rpm.spec"以及"rpmbuild -bb myapplication.rpm.spec"所顯示的輸出一樣。如果設置好了,沒有出錯的話,那麼此處就會在虛擬根目錄中安裝上相應的文件(也就是files指定的文件)。如果使用的是"rpmbuild -bb myapplication.rpm.spec"那麼就會繼續根據虛擬根目錄,製作相應的rpm包,存放在與BUILD目錄同級的RPMS下。
-
自定義"%{_topdir}"
# pwd /root/test/rpm_test/BUILD # echo %_topdir $(pwd)/../ >~/.rpmmacros # rpmbuild -bi myapplication.rpm.spec Executing(%prep): /bin/sh -e /var/tmp/rpm-tmp.18065 + umask 022 + cd /root/test/rpm_test/BUILD/..//BUILD + LANG=C + export LANG + unset DISPLAY ++ pwd + echo '======>In :prep section /root/test/rpm_test/BUILD' ======>In :prep section /root/test/rpm_test/BUILD + exit 0 Executing(%build): /bin/sh -e /var/tmp/rpm-tmp.18065 + umask 022 + cd /root/test/rpm_test/BUILD/..//BUILD + LANG=C + export LANG + unset DISPLAY ++ pwd + echo '======>In :build section /root/test/rpm_test/BUILD' ======>In :build section /root/test/rpm_test/BUILD + exit 0 Executing(%install): /bin/sh -e /var/tmp/rpm-tmp.18065 + umask 022 + cd /root/test/rpm_test/BUILD/..//BUILD + LANG=C + export LANG + unset DISPLAY ++ pwd + echo '======>In :install section /root/test/rpm_test/BUILD' ======>In :install section /root/test/rpm_test/BUILD + /usr/lib/rpm/redhat/brp-compress + /usr/lib/rpm/redhat/brp-strip /usr/bin/strip + /usr/lib/rpm/redhat/brp-strip-static-archive /usr/bin/strip + /usr/lib/rpm/redhat/brp-strip-comment-note /usr/bin/strip /usr/bin/objdump + /usr/lib/rpm/brp-python-bytecompile + /usr/lib/rpm/redhat/brp-java-repack-jars Processing files: myapplication-1.0-1 error: File not found: /var/tmp/myapplication-1.0-1-root/etc/myconfig1.conf error: File not found: /var/tmp/myapplication-1.0-1-root/etc/myconfig2.conf Executing(%doc): /bin/sh -e /var/tmp/rpm-tmp.18065 + umask 022 + cd /root/test/rpm_test/BUILD/..//BUILD + DOCDIR=/var/tmp/myapplication-1.0-1-root/usr/share/doc/myapplication-1.0 + export DOCDIR + rm -rf /var/tmp/myapplication-1.0-1-root/usr/share/doc/myapplication-1.0 + /bin/mkdir -p /var/tmp/myapplication-1.0-1-root/usr/share/doc/myapplication-1.0 + cp -pr README /var/tmp/myapplication-1.0-1-root/usr/share/doc/myapplication-1.0 + cp -pr Copyright /var/tmp/myapplication-1.0-1-root/usr/share/doc/myapplication-1.0 + exit 0 Checking for unpackaged file(s): /usr/lib/rpm/check-files /var/tmp/myapplication-1.0-1-root RPM build errors: File not found: /var/tmp/myapplication-1.0-1-root/etc/myconfig1.conf File not found: /var/tmp/myapplication-1.0-1-root/etc/myconfig2.conf
這裏,其實前面例子的"/usr/src/redhat"是"%{_topdir}",類似的變量有很多,不列舉了,具體可以查看"/usr/lib/rpm/macros"中的定義。如果修改它,就可以定義rpm默認的build路徑,默認爲/usr/src/redhat,所以我們這樣修改:
echo %_topdir $(pwd)/../ >~/.rpmmacros
當然,這假設當前路徑爲:"/root/test/rpm_test/BUILD",這樣執行prep,build,install等就會在當前路徑下進行而不是切換到默認的"/usr/src/redhat/BUILD"了。
-
一個好用的例子
這裏例子將展示把一個編譯好的可執行程序打包。
-
1)查看製作之前的目錄結構
# pwd /root/test/rpm_test # ls BUILD RPMS # tree BUILD/ RPMS BUILD/ |-- COPYRIGHT |-- Copyright |-- README |-- libmy.so |-- myapplication |-- myapplication.rpm.spec `-- myconfig.conf RPMS `-- i386 `-- myapplication-1.0-1.i386.rpm 1 directory, 8 files
-
2)建立的rpm的spec文件如下
# cd BUILD/ # cat myapplication.rpm.spec #+++++++++以下是文件內容+++++++++++# ######頭部###### Summary:一個簡單的打印hello的程序 Name:myapplication Version:1.0 Release:1 Vendor:QuietHeart ([email protected]) License:Share BuildRoot:%{_tmppath}/%{name}-%{version}-%{release}-root Group:Applications/Editors URL:quietheart.sf.net Prefix:%{_prefix} Prefix:%{_sysconfdir} Prefix:%{_datadir} Packager:QuietHeart %define myconfig myconfig.conf %define mylib libmy.so %description 描述省略。 ######prep,build,install三個段都可以執行shell命令###### # 預處理段,爲下一步的編譯安裝作準備。例如將源代碼拷貝到BUILDS目錄。 %prep # prep start. echo "======>In :prep section $(pwd)" echo "======>In :prep section " %{_topdir} echo "======>In :prep section $RPM_BUILD_ROOT" echo "======>In :prep section " %{_sourcedir} #echo "======>In :prep section $RPM_SOURCE_DIR" # 建立段,執行一些編譯命令以便生成軟件包。工作於BUILDS。 %build # build start. echo "======>In :build section $(pwd)" echo "======>In :build section " %{_topdir} echo "======>In :build section $RPM_BUILD_ROOT" echo "======>In :build section " %{_builddir} #echo "======>In :build section $RPM_BUILD_DIR" echo "nothing" >>README echo "By QuietHeart" >>COPYRIGHT # 安裝段,在安裝軟件包階段執行的命令。 # 安裝的內容安裝到“虛擬根目錄中”install是爲了後面的file段服務的。 %install # install start. echo "======>In :install section $(pwd)" echo "======>In :install section " %{_topdir} echo "======>In :install section $RPM_BUILD_ROOT" mkdir -p $RPM_BUILD_ROOT/usr/bin mkdir -p $RPM_BUILD_ROOT/usr/lib mkdir -p $RPM_BUILD_ROOT/etc #這裏使用%{name}表示開始定義的Name,即myapplication。 cp %{name} $RPM_BUILD_ROOT/usr/bin cp %{mylib} $RPM_BUILD_ROOT/usr/lib cp %{myconfig} $RPM_BUILD_ROOT/etc ######其它的一些段###### #製作完之後,會執行這裏,以便刪除例如$RPM_BUILD_ROOT之類的臨時文件。 %clean # clean start. echo "======>In :clean section $(pwd)" echo "======>In :clean section $RPM_BUILD_ROOT" #[ -d $RPM_BUILD_ROOT] && rm -rf $RPM_BUILD_ROOT #文件段,定義軟件包所包含的文件。具體可由後面"%defattr","%doc","%config"宏定義。 #主要包含:config(配置文件),doc(文檔文件),bin(二進制文件) %files #定義文件屬性:%defattr(權限,屬主,屬組)。其中權限'-'表默認,可用'0777'形式。 %defattr (-,root,root) #定義製作軟件包包含的文檔文件,每個宏定義一個,可指定絕對路徑。 #一般文檔文件會被安裝到"/usr/doc/Name-Version-Release"目錄下。 %doc README %doc Copyright #定義軟件包所需要的配置文件(還是安裝的配置文件位置??) #當卸載軟件的時候會將沒有修改過的卸掉,修改過的備份爲<name>.rpmsave。 %config %{_sysconfdir}/%{myconfig} #軟件包所包含的二進制文件,可以爲目錄 %{_bindir}/%{name} %{_libdir}/%{mylib} #修改日誌段,可以記錄每次的修改日誌。 #第一行是:* 星期 月 日 年 修改人 電子信箱。 #其中:星期、月份均用英文形式,用中文會出錯。 #接下來的行寫的應是修改了什麼地方,可寫多行。一般以減號起始,便於查閱。 #修改的時候,新的必須在上面。 %changelog *Fri Sep 30 2011 QuietHeart - 增加XXX內容2 *Fri Sep 29 2011 QuietHeart - 增加XXX內容1 #+++++++++以上是文件內容+++++++++++#
-
3)製作rpm包
# echo %_topdir $(pwd)/../ >~/.rpmmacros # rpmbuild -bb myapplication.rpm.spec Executing(%prep): /bin/sh -e /var/tmp/rpm-tmp.35758 + umask 022 + cd /root/test/rpm_test/BUILD/..//BUILD + LANG=C + export LANG + unset DISPLAY ++ pwd + echo '======>In :prep section /root/test/rpm_test/BUILD' ======>In :prep section /root/test/rpm_test/BUILD + echo '======>In :prep section ' /root/test/rpm_test/BUILD/../ ======>In :prep section /root/test/rpm_test/BUILD/../ + echo '======>In :prep section /var/tmp/myapplication-1.0-1-root' ======>In :prep section /var/tmp/myapplication-1.0-1-root + echo '======>In :prep section ' /root/test/rpm_test/BUILD/..//SOURCES ======>In :prep section /root/test/rpm_test/BUILD/..//SOURCES + exit 0 Executing(%build): /bin/sh -e /var/tmp/rpm-tmp.35758 + umask 022 + cd /root/test/rpm_test/BUILD/..//BUILD + LANG=C + export LANG + unset DISPLAY ++ pwd + echo '======>In :build section /root/test/rpm_test/BUILD' ======>In :build section /root/test/rpm_test/BUILD + echo '======>In :build section ' /root/test/rpm_test/BUILD/../ ======>In :build section /root/test/rpm_test/BUILD/../ + echo '======>In :build section /var/tmp/myapplication-1.0-1-root' ======>In :build section /var/tmp/myapplication-1.0-1-root + echo '======>In :build section ' /root/test/rpm_test/BUILD/..//BUILD ======>In :build section /root/test/rpm_test/BUILD/..//BUILD + echo nothing + echo 'By QuietHeart' + exit 0 Executing(%install): /bin/sh -e /var/tmp/rpm-tmp.35758 + umask 022 + cd /root/test/rpm_test/BUILD/..//BUILD + LANG=C + export LANG + unset DISPLAY ++ pwd + echo '======>In :install section /root/test/rpm_test/BUILD' ======>In :install section /root/test/rpm_test/BUILD + echo '======>In :install section ' /root/test/rpm_test/BUILD/../ ======>In :install section /root/test/rpm_test/BUILD/../ + echo '======>In :install section /var/tmp/myapplication-1.0-1-root' ======>In :install section /var/tmp/myapplication-1.0-1-root + mkdir -p /var/tmp/myapplication-1.0-1-root/usr/bin + mkdir -p /var/tmp/myapplication-1.0-1-root/usr/lib + mkdir -p /var/tmp/myapplication-1.0-1-root/etc + cp myapplication /var/tmp/myapplication-1.0-1-root/usr/bin + cp libmy.so /var/tmp/myapplication-1.0-1-root/usr/lib + cp myconfig.conf /var/tmp/myapplication-1.0-1-root/etc + /usr/lib/rpm/redhat/brp-compress + /usr/lib/rpm/redhat/brp-strip /usr/bin/strip + /usr/lib/rpm/redhat/brp-strip-static-archive /usr/bin/strip + /usr/lib/rpm/redhat/brp-strip-comment-note /usr/bin/strip /usr/bin/objdump + /usr/lib/rpm/brp-python-bytecompile + /usr/lib/rpm/redhat/brp-java-repack-jars Processing files: myapplication-1.0-1 Executing(%doc): /bin/sh -e /var/tmp/rpm-tmp.35758 + umask 022 + cd /root/test/rpm_test/BUILD/..//BUILD + DOCDIR=/var/tmp/myapplication-1.0-1-root/usr/share/doc/myapplication-1.0 + export DOCDIR + rm -rf /var/tmp/myapplication-1.0-1-root/usr/share/doc/myapplication-1.0 + /bin/mkdir -p /var/tmp/myapplication-1.0-1-root/usr/share/doc/myapplication-1.0 + cp -pr README /var/tmp/myapplication-1.0-1-root/usr/share/doc/myapplication-1.0 + cp -pr Copyright /var/tmp/myapplication-1.0-1-root/usr/share/doc/myapplication-1.0 + exit 0 Provides: config(myapplication) = 1.0-1 libmy.so Requires(rpmlib): rpmlib(CompressedFileNames) <= 3.0.4-1 rpmlib(PayloadFilesHavePrefix) <= 4.0-1 Requires: config(myapplication) = 1.0-1 libc.so.6 libc.so.6(GLIBC_2.0) libc.so.6(GLIBC_2.1.3) libgcc_s.so.1 libm.so.6 libmy.so libstdc++.so.6 libstdc++.so.6(CXXABI_1.3) libstdc++.so.6(GLIBCXX_3.4) rtld(GNU_HASH) Checking for unpackaged file(s): /usr/lib/rpm/check-files /var/tmp/myapplication-1.0-1-root warning: Could not canonicalize hostname: lv-k.domain.com Wrote: /root/test/rpm_test/RPMS/i386/myapplication-1.0-1.i386.rpm Executing(%clean): /bin/sh -e /var/tmp/rpm-tmp.13498 + umask 022 + cd /root/test/rpm_test/BUILD/..//BUILD ++ pwd + echo '======>In :clean section /root/test/rpm_test/BUILD' ======>In :clean section /root/test/rpm_test/BUILD + exit 0
-
4)查看製作結果
# tree ../BUILD/ ../RPMS ../BUILD/ |-- COPYRIGHT |-- Copyright |-- README |-- libmy.so |-- myapplication |-- myapplication.rpm.spec `-- myconfig.conf ../RPMS `-- i386 `-- myapplication-1.0-1.i386.rpm 1 directory, 8 files
可見,生成的結果在../RPMS/i386之中。
另外,根據spec文件,可知道,在"var/tmp/myapplication-1.0-1-root"下還生成一些製作rpm包時候的臨時文件,如下:
# tree /var/tmp/myapplication-1.0-1-root/ /var/tmp/myapplication-1.0-1-root/ |-- etc | `-- myconfig.conf `-- usr |-- bin | `-- myapplication |-- lib | `-- libmy.so `-- share `-- doc `-- myapplication-1.0 |-- Copyright `-- README 7 directories, 5 files
這些文件,可以在spec文件中的clean段裏面指定刪除。另外還需要注意的是,這裏使用rpmbuild的-bb選項,如果使用-ba的話也會報錯,如下:
# rpmbuild -ba myapplication.rpm.spec ...前面省略... ======>In :install section /var/tmp/myapplication-1.0-1-root + mkdir -p /var/tmp/myapplication-1.0-1-root/usr/bin + mkdir -p /var/tmp/myapplication-1.0-1-root/usr/lib + mkdir -p /var/tmp/myapplication-1.0-1-root/etc + cp myapplication /var/tmp/myapplication-1.0-1-root/usr/bin + cp libmy.so /var/tmp/myapplication-1.0-1-root/usr/lib + cp myconfig.conf /var/tmp/myapplication-1.0-1-root/etc + /usr/lib/rpm/redhat/brp-compress + /usr/lib/rpm/redhat/brp-strip /usr/bin/strip + /usr/lib/rpm/redhat/brp-strip-static-archive /usr/bin/strip + /usr/lib/rpm/redhat/brp-strip-comment-note /usr/bin/strip /usr/bin/objdump + /usr/lib/rpm/brp-python-bytecompile + /usr/lib/rpm/redhat/brp-java-repack-jars Processing files: myapplication-1.0-1 Executing(%doc): /bin/sh -e /var/tmp/rpm-tmp.6317 + umask 022 + cd /root/test/rpm_test/BUILD/..//BUILD + DOCDIR=/var/tmp/myapplication-1.0-1-root/usr/share/doc/myapplication-1.0 + export DOCDIR + rm -rf /var/tmp/myapplication-1.0-1-root/usr/share/doc/myapplication-1.0 + /bin/mkdir -p /var/tmp/myapplication-1.0-1-root/usr/share/doc/myapplication-1.0 + cp -pr README /var/tmp/myapplication-1.0-1-root/usr/share/doc/myapplication-1.0 + cp -pr Copyright /var/tmp/myapplication-1.0-1-root/usr/share/doc/myapplication-1.0 + exit 0 Provides: config(myapplication) = 1.0-1 libmy.so Requires(rpmlib): rpmlib(CompressedFileNames) <= 3.0.4-1 rpmlib(PayloadFilesHavePrefix) <= 4.0-1 Requires: config(myapplication) = 1.0-1 libc.so.6 libc.so.6(GLIBC_2.0) libc.so.6(GLIBC_2.1.3) libgcc_s.so.1 libm.so.6 libmy.so libstdc++.so.6 libstdc++.so.6(CXXABI_1.3) libstdc++.so.6(GLIBCXX_3.4) rtld(GNU_HASH) Checking for unpackaged file(s): /usr/lib/rpm/check-files /var/tmp/myapplication-1.0-1-root warning: Could not canonicalize hostname: lv-k.domain.com error: Could not open /root/test/rpm_test/SRPMS/myapplication-1.0-1.src.rpm: 沒有那個文件或目錄
-
5)使用製作好的rpm包
-
查看軟件包頭
# rpm -qpi ../RPMS/i386/myapplication-1.0-1.i386.rpm Name : myapplication Relocations: /usr /etc /usr/share Version : 1.0 Vendor: QuietHeart ([email protected]) Release : 1 Build Date: 2011年10月07日 星期五 14時40分35秒 Install Date: (not installed) Build Host: lv-k.domain.com Group : Applications/Editors Source RPM: myapplication-1.0-1.src.rpm Size : 12504 License: Share Signature : (none) Packager : QuietHeart URL : quietheart.sf.net Summary : 一個簡單的打印hello的程序 Description : 描述省略。
-
查看軟件包的全部文件列表
# rpm -qpl ../RPMS/i386/myapplication-1.0-1.i386.rpm /etc/myconfig.conf /usr/bin/myapplication /usr/lib/libmy.so /usr/share/doc/myapplication-1.0 /usr/share/doc/myapplication-1.0/Copyright /usr/share/doc/myapplication-1.0/README
這裏,顯示的就是安裝軟件將要向哪些目錄安裝什麼文件。
-
安裝軟件
# rpm -ivh ../RPMS/i386/myapplication-1.0-1.i386.rpm Preparing... ########################################### [100%] 1:myapplication ########################################### [100%]
-
查詢被安裝的軟件
# rpm -qa |grep myapplication myapplication-1.0-1
-
運行軟件
# myapplication begin test hello
這裏,軟件源代碼省略,以後會有更詳細的講解。
-
卸載軟件
# rpm -e myapplication-1.0-1
-
一個較完整的例子
這裏是一個較完整的製作rpm軟件包的例子,先只給出簡單過程,然後詳細介紹。
-
a,最簡過程
# pwd /root/test/rpm_test # tree . |-- BUILD |-- RPMS | `-- i386 |-- SOURCES | `-- myapplication-1.0.tgz |-- SPECS | `-- myapplication.rpm.spec `-- SRPMS 6 directories, 2 files # echo %_topdir $(pwd) >~/.rpmmacrosmacros # rpmbuild -ba SPECS/myapplication.rpm.spec # tree . |-- BUILD | `-- myapplication-1.0 | |-- COPYRIGHT | |-- Makefile | |-- README | |-- debugfiles.list | |-- debuglinks.list | |-- debugsources.list | |-- lib | | |-- Makefile | | |-- libmy.so | | |-- myfile.cpp | | |-- myfile.h | | `-- myfile.o | |-- main.cpp | |-- main.o | |-- myapplication | |-- myconfig.conf | `-- myfile.h |-- RPMS | `-- i386 | |-- myapplication-1.0-1.i386.rpm | `-- myapplication-debuginfo-1.0-1.i386.rpm |-- SOURCES | `-- myapplication-1.0.tgz |-- SPECS | `-- myapplication.rpm.spec `-- SRPMS `-- myapplication-1.0-1.src.rpm 8 directories, 21 files
-
b,詳細過程
-
1)查看文件結構
# pwd /root/test/rpm_test # tree . |-- BUILD |-- RPMS | `-- i386 |-- SOURCES | `-- myapplication-1.0.tgz |-- SPECS | `-- myapplication.rpm.spec `-- SRPMS 6 directories, 2 files
-
2)源代碼和rpm的spec文件內容
-
2.1)源代碼文件相關
假設將SOURCES/myapplication-1.0.tgz解壓(實際運行"rpm -bp"的時候就是這樣做的,並且解到BUILD供後面的步驟使用),
#tree myapplication myapplication-1.0 |-- COPYRIGHT |-- Makefile |-- README |-- lib | |-- Makefile | |-- myfile.cpp | `-- myfile.h |-- main.cpp |-- myconfig.conf `-- myfile.h 1 directory, 9 files
每個文件內容依次如下:
# cat myapplication-1.0/COPYRIGHT By QuietHeart # cat myapplication-1.0/Makefile myapplication:main.o libmy.so g++ main.o -L./lib/ -lmy -o myapplication main.o:main.cpp libmy.so: make -C ./lib .PHONY:clean clean: make -C ./lib clean rm *.o myapplication # cat myapplication-1.0/README nothing # cat myapplication-1.0/main.cpp #include<iostream> #include "myfile.h" using std::cout; using std::endl; int main(int argc, char *argv[]) { cout<<"begin test"<<endl; printInfo(); return 0; } # cat myapplication-1.0/myconfig.conf configure content # cat myapplication-1.0/myfile.h #ifndef __MYFILE_H #define __MYFILE_H void printInfo(); #endif # cat myapplication-1.0/lib/Makefile libmy.so:myfile.o g++ -shared -o libmy.so myfile.o myfile.o:myfile.cpp .PHONY:clean clean: rm *.so *.o # cat myapplication-1.0/lib/myfile.cpp #include "myfile.h" #include <iostream> using std::cout; using std::endl; void printInfo() { cout<<"hello"<<endl; } # cat myapplication-1.0/lib/myfile.h #ifndef __MYFILE_H #define __MYFILE_H void printInfo(); #endif
-
2.2)spec文件相關
# tree SPECS/ SPECS/ `-- myapplication.rpm.spec 0 directories, 1 file
查看其文件內容如下:
# cat SPECS/myapplication.rpm.spec ######頭部###### Summary:一個簡單的打印hello的程序 Name:myapplication Version:1.0 Release:1 Vendor:QuietHeart ([email protected]) License:Share SOURCE:%{name}-%{version}.tgz BuildRoot:%{_tmppath}/%{name}-%{version}-%{release}-root Group:Applications/Editors URL:quietheart.sf.net Prefix:%{_prefix} Prefix:%{_sysconfdir} Prefix:%{_datadir} Packager:QuietHeart %define myconfig myconfig.conf %define mylib libmy.so %description 描述省略。 ######prep,build,install三個段都可以執行shell命令###### # 預處理段,爲下一步的編譯安裝作準備。例如將源代碼拷貝到BUILDS目錄。 %prep # prep start. echo "======>In :prep section $(pwd)" echo "======>In :prep section " %{_topdir} echo "======>In :prep section $RPM_BUILD_ROOT" echo "======>In :prep section " %{_sourcedir} #echo "======>In :prep section $RPM_SOURCE_DIR" #將源代碼包解壓並放好,也可以使用tar命令,解壓好的目錄:%{name}-%{version},存在BUILD中。 %setup -n %{name}-%{version} #tar -xzvf %{_sourcedir}/%{name}-%{version}.tgz -C %{_builddir} # 建立段,執行一些編譯命令以便生成軟件包。工作於BUILDS。 %build # build start. echo "======>In :build section $(pwd)" echo "======>In :build section " %{_topdir} echo "======>In :build section $RPM_BUILD_ROOT" echo "======>In :build section " %{_builddir} #echo "======>In :build section $RPM_BUILD_DIR" #自動進入myapplication-1.0中了。 make # 安裝段,在安裝軟件包階段執行的命令。 # 安裝的內容安裝到“虛擬根目錄中”install是爲了後面的file段服務的。 %install # install start. echo "======>In :install section $(pwd)" echo "======>In :install section " %{_topdir} echo "======>In :install section $RPM_BUILD_ROOT" mkdir -p $RPM_BUILD_ROOT/usr/bin mkdir -p $RPM_BUILD_ROOT/usr/lib mkdir -p $RPM_BUILD_ROOT/etc #這裏使用%{name}表示開始定義的Name,即myapplication。 cp %{name} $RPM_BUILD_ROOT/usr/bin cp lib/%{mylib} $RPM_BUILD_ROOT/usr/lib cp %{myconfig} $RPM_BUILD_ROOT/etc ######其它的一些段###### %clean # clean start. echo "======>In :clean section $(pwd)" #文件段,定義軟件包所包含的文件。具體可由後面"%defattr","%doc","%config"宏定義。 #主要包含:config(配置文件),doc(文檔文件),bin(二進制文件) %files #定義文件屬性:%defattr(權限,屬主,屬組)。其中權限'-'表默認,可用'0777'形式。 %defattr (-,root,root) #定義製作軟件包包含的文檔文件,每個宏定義一個,可指定絕對路徑。 #一般文檔文件會被安裝到"/usr/doc/Name-Version-Release"目錄下。 %doc README %doc COPYRIGHT #定義軟件包所需要的配置文件(還是安裝的配置文件位置??) #當卸載軟件的時候會將沒有修改過的卸掉,修改過的備份爲<name>.rpmsave。 %config %{_sysconfdir}/%{myconfig} #軟件包所包含的二進制文件,可以爲目錄 %{_bindir}/%{name} %{_libdir}/%{mylib} #修改日誌段,可以記錄每次的修改日誌。 #第一行是:* 星期 月 日 年 修改人 電子信箱。 #其中:星期、月份均用英文形式,用中文會出錯。 #接下來的行寫的應是修改了什麼地方,可寫多行。一般以減號起始,便於查閱。 #修改的時候,新的必須在上面。 %changelog *Fri Sep 30 2011 QuietHeart - 增加XXX內容2 *Fri Sep 29 2011 QuietHeart - 增加XXX內容1
-
-
3)製作rpm包
# echo %_topdir $(pwd) >~/.rpmmacrosmacros # rpmbuild -ba SPECS/myapplication.rpm.spec Executing(%prep): /bin/sh -e /var/tmp/rpm-tmp.87076 + umask 022 + cd /root/test/rpm_test/BUILD/..//BUILD + LANG=C + export LANG + unset DISPLAY ++ pwd + echo '======>In :prep section /root/test/rpm_test/BUILD' ======>In :prep section /root/test/rpm_test/BUILD + echo '======>In :prep section ' /root/test/rpm_test/BUILD/../ ======>In :prep section /root/test/rpm_test/BUILD/../ + echo '======>In :prep section /var/tmp/myapplication-1.0-1-root' ======>In :prep section /var/tmp/myapplication-1.0-1-root + echo '======>In :prep section ' /root/test/rpm_test/BUILD/..//SOURCES ======>In :prep section /root/test/rpm_test/BUILD/..//SOURCES + cd /root/test/rpm_test/BUILD + rm -rf myapplication-1.0 + /bin/gzip -dc /root/test/rpm_test/SOURCES/myapplication-1.0.tgz + tar -xvvf - drwxrwxrwx root/root 0 2011-10-07 15:29:19 myapplication-1.0/ -rw-r--r-- root/root 14 2011-10-07 15:28:56 myapplication-1.0/COPYRIGHT drwxrwxrwx root/root 0 2011-10-07 15:16:34 myapplication-1.0/lib/ -rwxrwxrwx root/root 117 2009-11-21 17:12:18 myapplication-1.0/lib/myfile.cpp -rwxr-xr-x root/root 63 2011-09-29 18:17:29 myapplication-1.0/lib/myfile.h -rw-r--r-- root/root 106 2011-10-07 15:16:29 myapplication-1.0/lib/Makefile -rwxrwxrwx root/root 63 2009-11-21 17:12:18 myapplication-1.0/myfile.h -rw-r--r-- root/root 8 2011-10-07 15:28:51 myapplication-1.0/README -rw-r--r-- root/root 18 2011-10-07 15:29:19 myapplication-1.0/myconfig.conf -rwxrwxrwx root/root 1734 2009-12-10 09:09:06 myapplication-1.0/main.cpp -rw-r--r-- root/root 178 2011-10-07 15:16:07 myapplication-1.0/Makefile + STATUS=0 + '[' 0 -ne 0 ']' + cd myapplication-1.0 ++ /usr/bin/id -u + '[' 0 = 0 ']' + /bin/chown -Rhf root . ++ /usr/bin/id -u + '[' 0 = 0 ']' + /bin/chgrp -Rhf root . + /bin/chmod -Rf a+rX,u+w,g-w,o-w . + exit 0 Executing(%build): /bin/sh -e /var/tmp/rpm-tmp.87076 + umask 022 + cd /root/test/rpm_test/BUILD/..//BUILD + cd myapplication-1.0 + LANG=C + export LANG + unset DISPLAY ++ pwd + echo '======>In :build section /root/test/rpm_test/BUILD/myapplication-1.0' ======>In :build section /root/test/rpm_test/BUILD/myapplication-1.0 + echo '======>In :build section ' /root/test/rpm_test/BUILD/../ ======>In :build section /root/test/rpm_test/BUILD/../ + echo '======>In :build section /var/tmp/myapplication-1.0-1-root' ======>In :build section /var/tmp/myapplication-1.0-1-root + echo '======>In :build section ' /root/test/rpm_test/BUILD/..//BUILD ======>In :build section /root/test/rpm_test/BUILD/..//BUILD + make g++ -c -o main.o main.cpp make -C ./lib make[1]: Entering directory `/root/test/rpm_test/BUILD/myapplication-1.0/lib' g++ -c -o myfile.o myfile.cpp g++ -shared -o libmy.so myfile.o make[1]: Leaving directory `/root/test/rpm_test/BUILD/myapplication-1.0/lib' g++ main.o -L./lib/ -lmy -o myapplication + exit 0 Executing(%install): /bin/sh -e /var/tmp/rpm-tmp.83304 + umask 022 + cd /root/test/rpm_test/BUILD/..//BUILD + cd myapplication-1.0 + LANG=C + export LANG + unset DISPLAY ++ pwd + echo '======>In :install section /root/test/rpm_test/BUILD/myapplication-1.0' ======>In :install section /root/test/rpm_test/BUILD/myapplication-1.0 + echo '======>In :install section ' /root/test/rpm_test/BUILD/../ ======>In :install section /root/test/rpm_test/BUILD/../ + echo '======>In :install section /var/tmp/myapplication-1.0-1-root' ======>In :install section /var/tmp/myapplication-1.0-1-root + mkdir -p /var/tmp/myapplication-1.0-1-root/usr/bin + mkdir -p /var/tmp/myapplication-1.0-1-root/usr/lib + mkdir -p /var/tmp/myapplication-1.0-1-root/etc + cp myapplication /var/tmp/myapplication-1.0-1-root/usr/bin + cp lib/libmy.so /var/tmp/myapplication-1.0-1-root/usr/lib + cp myconfig.conf /var/tmp/myapplication-1.0-1-root/etc + /usr/lib/rpm/find-debuginfo.sh /root/test/rpm_test/BUILD/..//BUILD/myapplication-1.0 + /usr/lib/rpm/redhat/brp-compress + /usr/lib/rpm/redhat/brp-strip-static-archive /usr/bin/strip + /usr/lib/rpm/redhat/brp-strip-comment-note /usr/bin/strip /usr/bin/objdump + /usr/lib/rpm/brp-python-bytecompile + /usr/lib/rpm/redhat/brp-java-repack-jars Processing files: myapplication-1.0-1 Executing(%doc): /bin/sh -e /var/tmp/rpm-tmp.83304 + umask 022 + cd /root/test/rpm_test/BUILD/..//BUILD + cd myapplication-1.0 + DOCDIR=/var/tmp/myapplication-1.0-1-root/usr/share/doc/myapplication-1.0 + export DOCDIR + rm -rf /var/tmp/myapplication-1.0-1-root/usr/share/doc/myapplication-1.0 + /bin/mkdir -p /var/tmp/myapplication-1.0-1-root/usr/share/doc/myapplication-1.0 + cp -pr README /var/tmp/myapplication-1.0-1-root/usr/share/doc/myapplication-1.0 + cp -pr COPYRIGHT /var/tmp/myapplication-1.0-1-root/usr/share/doc/myapplication-1.0 + exit 0 Provides: config(myapplication) = 1.0-1 libmy.so Requires(rpmlib): rpmlib(CompressedFileNames) <= 3.0.4-1 rpmlib(PayloadFilesHavePrefix) <= 4.0-1 Requires: config(myapplication) = 1.0-1 libc.so.6 libc.so.6(GLIBC_2.0) libc.so.6(GLIBC_2.1.3) libgcc_s.so.1 libm.so.6 libmy.so libstdc++.so.6 libstdc++.so.6(CXXABI_1.3) libstdc++.so.6(GLIBCXX_3.4) rtld(GNU_HASH) Processing files: myapplication-debuginfo-1.0-1 Provides: libmy.so.debug Requires(rpmlib): rpmlib(CompressedFileNames) <= 3.0.4-1 rpmlib(PayloadFilesHavePrefix) <= 4.0-1 Checking for unpackaged file(s): /usr/lib/rpm/check-files /var/tmp/myapplication-1.0-1-root warning: Could not canonicalize hostname: lv-k.domain.com Wrote: /root/test/rpm_test/SRPMS/myapplication-1.0-1.src.rpm Wrote: /root/test/rpm_test/RPMS/i386/myapplication-1.0-1.i386.rpm Wrote: /root/test/rpm_test/RPMS/i386/myapplication-debuginfo-1.0-1.i386.rpm Executing(%clean): /bin/sh -e /var/tmp/rpm-tmp.76622 + umask 022 + cd /root/test/rpm_test/BUILD/..//BUILD + cd myapplication-1.0 ++ pwd + echo '======>In :clean section /root/test/rpm_test/BUILD/myapplication-1.0' ======>In :clean section /root/test/rpm_test/BUILD/myapplication-1.0 + exit 0
-
4)查看生成的文件
# tree . |-- BUILD | `-- myapplication-1.0 | |-- COPYRIGHT | |-- Makefile | |-- README | |-- debugfiles.list | |-- debuglinks.list | |-- debugsources.list | |-- lib | | |-- Makefile | | |-- libmy.so | | |-- myfile.cpp | | |-- myfile.h | | `-- myfile.o | |-- main.cpp | |-- main.o | |-- myapplication | |-- myconfig.conf | `-- myfile.h |-- RPMS | `-- i386 | |-- myapplication-1.0-1.i386.rpm | `-- myapplication-debuginfo-1.0-1.i386.rpm |-- SOURCES | `-- myapplication-1.0.tgz |-- SPECS | `-- myapplication.rpm.spec `-- SRPMS `-- myapplication-1.0-1.src.rpm 8 directories, 21 files
由上面可見,生成的文件分別是:
- BUILD/myapplication-1.0目錄,在prep段指定的命令中解壓SOURCES目錄中的內容生成。
- RPMS/i386/*.rpm,製作後期二進制rpm包生成。(可以用"rpmbuild -bb"單獨生成這個)。
- SRPMS/*.rpm,製作後期源碼rpm包生成。(可以用"rpmbuild -bs"單獨生成這個)。
-
5)使用製作的rpm包
-
查看軟件包頭
# rpm -qpi RPMS/i386/myapplication-1.0-1.i386.rpm Name : myapplication Relocations: /usr /etc /usr/share Version : 1.0 Vendor: QuietHeart ([email protected]) Release : 1 Build Date: 2011年10月07日 星期五 16時13分09秒 Install Date: (not installed) Build Host: lv-k.domain.com Group : Applications/Editors Source RPM: myapplication-1.0-1.src.rpm Size : 12580 License: Share Signature : (none) Packager : QuietHeart URL : quietheart.sf.net Summary : 一個簡單的打印hello的程序 Description : 描述省略。
-
查看軟件包的全部文件列表
# rpm -qpl RPMS/i386/myapplication-1.0-1.i386.rpm /etc/myconfig.conf /usr/bin/myapplication /usr/lib/libmy.so /usr/share/doc/myapplication-1.0 /usr/share/doc/myapplication-1.0/COPYRIGHT /usr/share/doc/myapplication-1.0/README
這裏,顯示的就是安裝軟件將要向哪些目錄安裝什麼文件。
-
安裝軟件
# rpm -ivh RPMS/i386/myapplication-1.0-1.i386.rpm Preparing... ########################################### [100%] 1:myapplication ########################################### [100%]
-
指定前綴的安裝軟件
# rpm -ivh --relocate=/usr=/root/myprefix/usr --relocate=/etc=/root/myprefix/etc myapplication-1.0-1.i386.rpm Preparing... ########################################### [100%] 1:myapplication ########################################### [100%]
這裏,因爲spec中指定了多個Prefix,所以使用這個方式進行指定前綴,如果使用"–prefix",那麼會如下:
# rpm -ivh --prefix=/root/myprefix myapplication-1.0-1.i386.rpm error: package myapplication is not relocatable
使用–relocate指定之後,查看安裝好的路徑,如下:
# tree /root/myprefix/ /root/myprefix/ |-- etc | `-- myconfig.conf `-- usr |-- bin | `-- myapplication |-- lib | `-- libmy.so `-- share `-- doc `-- myapplication-1.0 |-- COPYRIGHT `-- README 7 directories, 5 files
實踐發現,如果不存在/root/myprefix會自動創建,如果使用"rpm -e"卸載這樣安裝的軟件,那麼只是刪除了/root/myprefix,但是目錄卻保留,如下:
# tree /root/myprefix/ /root/myprefix/ |-- etc `-- usr |-- bin |-- lib `-- share `-- doc 6 directories, 0 files
另外,如果卸之前修改了/etc文件,那麼會提示,如下:
# rpm -e myapplication-1.0-1 warning: /root/myprefix/etc/myconfig.conf saved as /root/myprefix/etc/myconfig.conf.rpmsave # tree /root/myprefix/ /root/myprefix/ |-- etc | `-- myconfig.conf.rpmsave `-- usr |-- bin |-- lib `-- share `-- doc 6 directories, 1 file
-
查詢被安裝的軟件
# rpm -qa |grep myapplication myapplication-1.0-1
-
運行軟件
# myapplication begin test hello
這裏,軟件源代碼省略,以後會有更詳細的講解。
-
卸載軟件
# rpm -e myapplication-1.0-1
-
查看源碼包頭
# rpm -qpi SRPMS/myapplication-1.0-1.src.rpm Name : myapplication Relocations: (not relocatable) Version : 1.0 Vendor: QuietHeart ([email protected]) Release : 1 Build Date: 2011年10月07日 星期五 16時13分09秒 Install Date: (not installed) Build Host: lv-k.domain.com Group : Applications/Editors Source RPM: (none) Size : 5084 License: Share Signature : (none) Packager : QuietHeart URL : quietheart.sf.net Summary : 一個簡單的打印hello的程序 Description : 描述省略。
-
查看源碼包文件列表
# rpm -qpi SRPMS/myapplication-1.0-1.src.rpm myapplication-1.0.tgz myapplication.rpm.spec
-
安裝源碼包
# rpm -ivh SRPMS/myapplication-1.0-1.src.rpm 1:myapplication ########################################### [100%]
-
查看剛剛的安裝
# rpm -qa |grep myapplication
這裏,看不出來,究竟安裝到了哪裏。但是實際上,是安裝到了SOURCES中和SPECS中了,如果將SOURCES和SPECS中原來的刪掉,再安裝,就能夠看出來了。
-
-