RPM相關知識

MichaelXoX發表於2018-06-20

RPM相關知識

一、RPM工具功能

我們可以直接使用rpm命令,對軟體包進行一些操作。

安裝

rpm –ivh <package_name>
–nodeps忽略依賴問題,一般僅用於測試

解除安裝

rpm –e <package_name>
有其它包依賴此RPM包時,解除安裝會報錯

升級

升級時使用-ivh會提示檔案衝突
rpm –Uvh <package_name> 沒有安裝過,則安裝
rpm –Fvh <package_name> 沒有安裝過,則忽略

查詢

rpm –q[option] <package name>
-q 僅查詢是否安裝
-qi 列出軟體包的詳細資訊
-ql 列出軟體包的目錄及檔案
-qf 列出檔案對應的安裝包
-qa 列出所有已安裝的軟體包
-qp 列出未安裝的RPM包的資訊

驗證

對已安裝的包進行檔案校驗:
rpm –V <package_name>
rpm -Vp <rpm_file>
rpm -Va
匯入key:
rpm –import <RPM_KEY>
在包安裝之前進行簽名校驗:
rpm -K <rpm_>file

重建資料庫

rpm –rebuilddb 解決系統RPM資料庫的異常

二、基本YUM命令

yum其實是透明的呼叫rpm,相當於在rpm基礎上封裝的更易使用的“前端”。

它主要設計來解決軟體包之間的依賴性,並可從多個資源庫(我們稱之為“源”,典型的由/etc/yum.repos.d/目錄下的每個.repo檔案定義)。

2.1源製作

createrepo <dir>
一般的centos系的iso映象中,都帶有安裝時使用的rpm包。可以將這部分檔案mount到本地,建立本地源,以減少軟體安裝時的上網下載。

2.2 安裝

yum install <package_name> -y
yum localinstall <rpm_file> 本地安裝
yum groupinstall <group_name> 組安裝

2.3 升級

yum update [package_name]

2.4 解除安裝

yum remove/erase <package_name>
謹慎使用: 此命令會解除安裝掉所有依賴此包的RPM包
查詢
yum search <name>
yum list|grep

2.5 本地快取相關

yum makecache 只做本地快取
yum clean all 清除本地快取

三、spec檔案

製作RPM軟體包並不是一件複雜的工作,其中的關鍵在於編寫SPEC軟體包描述檔案。要想製作一個rpm軟體包就必須寫一個軟體包描述檔案(SPEC)。這個檔案中包含了軟體包的諸多資訊,如軟體包的名字、版本、類別、說明摘要、建立時要執行什麼指令、安裝時要執行什麼操作、以及軟體包所要包含的檔案列表等等。

實際過程中,最關鍵的地方,是要清楚虛擬路徑的位置,以及巨集的定義。

3.1 檔案頭

  • Summary:用一句話概括該軟體包儘量多的資訊。
  • Name:軟體包的名字,最終RPM軟體包是用該名字與版本號,釋出號及體系號來命名軟體包的,後面可使用%{name}的方式引用
  • Version:軟體版本號。僅當軟體包比以前有較大改變時才增加版本號,後面可使用%{version}引用
  • Release:軟體包釋出號、發行號。一般我們對該軟體包做了一些小的補丁的時候就應該把釋出號加1,後面可使用%{release}引用
  • Packager:打包的人(一般喜歡寫個人郵箱)
  • Vendor:軟體開發者的名字,發行商或打包組織的資訊,例如RedFlagCo,Ltd
  • License:軟體授權方式,通常是GPL(自由軟體)或GPLv2,BSD
  • Copyright:軟體包所採用的版權規則。具體有:GPL(自由軟體),BSD,MIT,Public Domain(公共域),Distributable(貢獻),commercial(商業),Share(共享)等,一般的開發都寫GPL。
  • Group:軟體包所屬類別
  • Source:源程式軟體包的名字/原始碼包的名字。如 stardict-2.0.tar.gz。格式:Source0: %{name}-%{version}.tar.gz,原始碼包,可以帶多個用Source1、Source2等源,後面也可以用%{source1}、%{source2}引用。要注意的是,不要在 Source 語句中包含任何路徑
  • BuildArch: 指編譯的目標處理器架構,noarch標識不指定,但通常都是以/usr/lib/rpm/marcros中的內容為預設值
  • %description:軟體包詳細說明,可寫在多個行上。這樣任何人使用 rpm -qi查詢您的軟體包時都可以看到它。您可以解釋這個軟體包做什麼,描述任何警告或附加的配置指令,等等。
  • BuildRoot:編譯的路徑。是安裝或編譯時使用的“虛擬目錄”,考慮到多使用者的環境,一般定義為:%{_tmppath}/%{name}-%{version}-%{release}-root。該引數非常重要,因為在生成rpm的過程中,執行make install時就會把軟體安裝到上述的路徑中,在打包的時候,同樣依賴“虛擬目錄”為“根目錄”進行操作(即%files段)。後面可使用$RPM_BUILD_ROOT方式引用。
  • URL:軟體的主頁

3.2 依賴關係

依賴關係定義了一個包正常工作需要依賴的其他包,RPM在升級、安裝和刪除的時候會確保依賴關係得到滿足。rpm支援4種依賴:

  • Requirements, 包依賴其他包所提供的功能
  • Provides, 這個包能提供的功能
  • Conflicts, 一個包和其他包衝突的功能
  • Obsoletes, 其他包提供的功能已經不推薦使用了,這通常是其他包的功能修改了,老版本不推薦使用了,可以在以後的版本中會被廢棄。

3.2.1 定義依賴關係的語法是:

Requires: capability
Provides: capability
Obsoletes: capability
Conflicts: capability

大部分時候,capability應該是所依賴的包的名稱。一行中也可以定義多個依賴,比如:

Requires: tbsys tbnet

在指定依賴關係的時候還可以指定版本號,比如:

Requires: tbsys >= 2.0

3.2.2 Requires

定義安裝時的依賴包, 可以用>=或<=表示大於或小於某一特定版本。 “>=”號兩邊需用空格隔開,而不同軟體名稱也用空格分開。

格式:

Requires:       libpng-devel >= 1.0.20 zlib

其它寫法例如:

Requires: bzip2 = %{version}, bzip2-libs =%{version}

還有例如PreReqRequires(pre)Requires(post)Requires(preun)Requires(postun)BuildRequires等都是針對不同階段的依賴指定。

關於prepostpreunpostun含義理解,感覺post有一種“完成”的意思:

# 安裝前執行的指令碼,語法和shell指令碼的語法相同
%pre
# 安裝後執行的指令碼
%post
# 解除安裝前執行的指令碼
%preun
# 解除安裝完成後執行的指令碼
%postun
# 清理階段,在製作完成後刪除安裝的內容

例如:

PreReq: capability>=version      #capability包必須先安裝
Conflicts:bash>=2.0              #該包和所有不小於2.0的bash包有衝突

3.2.3 BuildRequires

定義打包時依賴的軟體包。

下面介紹spec指令碼主體:

3.3 %prep段

這個段是預處理段,通常用來執行一些解開源程式包的命令,為下一步的編譯安裝作準備。%prep和下面的%build%install段一樣,除了可以執行RPM所定義的巨集命令(以%開頭)以外,還可以執行SHELL命令,命令可以有很多行,如我們常寫的tar解包命令。功能上類似於./configure

Prep 節進行實際的打包準備工作,它是使用節字首%prep表示的。主要功能有:

  • 將檔案 (SOURCES/) 解壓到構建目錄 (BUILD/)
  • 應用Patch(打補丁) (SOURCES/ => BUILD/)
  • 描述 “rm -rf $RPM_BUILD_ROOT”
  • 描述或編輯本部分用到的命令到 PreReq:
  • 通過 “-b .XXX” 描述補丁備份

它一般包含%setup%patch兩個命令。%setup用於將軟體包開啟,執行%patch可將補丁檔案加入解開的源程式中。

3.3.1 巨集%setup

這個巨集解壓原始碼,將當前目錄改為原始碼解壓之後產生的目錄。這個巨集還有一些選項可以用。例如,在解壓後,%setup巨集假設產生的目錄是%{name}-%{version}

%setup -n %{name}-%{version} #把原始碼包解壓並放好

通常是從/usr/src/asianux/SOURCES裡的包解壓到/usr/src/asianux/BUILD/%{name}-%{version}中。一般用%setup -c就可以了,但有兩種情況:一就是同時編譯多個原始碼包,二就是原始碼的tar包的名稱與解壓出來的目錄不一致,此時,就需要使用-n引數指定一下了。

引用

%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 將所有打補丁時產生的輸出檔案刪除

%configure 這個不是關鍵字,而是rpm定義的標準巨集命令。意思是執行原始碼的configure配置.

/usr/src/asianux/BUILD/%{name}-%{version}目錄中進行 ,使用標準寫法,會引用/usr/lib/rpm/marcros中定義的引數。

3.3.2 巨集%patch

這個巨集將頭部定義的補丁應用於原始碼。如果定義了多個補丁,它可以用一個數字的引數來指示應用哪個補丁檔案。它也接受 -b extension 引數,指示 RPM 在打補丁之前,將檔案備份為副檔名是 extension 的檔案。

通常補丁都會一起在原始碼tar.gz包中,或放到SOURCES目錄下。一般引數為:
%patch -p1 使用前面定義的Patch補丁進行,-p1是忽略patch的第一層目錄
%Patch2 -p1 -b xxx.patch打上指定的補丁,-b是指生成備份檔案

3.3.3 補充-巨集

所有巨集都可以在/usr/lib/rpm/macros找到,附錄一些常見的巨集:

%{_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 
%{_topdir}            %{getenv:HOME}/rpmbuild
%{_builddir}          %{_topdir}/BUILD
%{_rpmdir}            %{_topdir}/RPMS
%{_sourcedir}         %{_topdir}/SOURCES
%{_specdir}           %{_topdir}/SPECS
%{_srcrpmdir}         %{_topdir}/SRPMS
%{_buildrootdir}      %{_topdir}/BUILDROOT
%{_var}               /var
%{_tmppath}           %{_var}/tmp
%{_usr}               /usr
%{_usrsrc}            %{_usr}/src
%{_docdir}            %{_datadir}/doc

利用 rpmbuild 構建 rpm 安裝包時,通過命令rpm --showrc檢視實現程式碼。另外直接通過 rpm --eval "%{macro}"來檢視具體對應路徑。

比如我們要檢視%{_bindir}的路徑,就可以使用命令rpm --eval "%{ _bindir}"來檢視

%{_topdir}            %{getenv:HOME}/rpmbuild
%{_builddir}          %{_topdir}/BUILD
%{_rpmdir}            %{_topdir}/RPMS
%{_sourcedir}         %{_topdir}/SOURCES
%{_specdir}           %{_topdir}/SPECS
%{_srcrpmdir}         %{_topdir}/SRPMS
%{_buildrootdir}      %{_topdir}/BUILDROOT

Note: On releases older than Fedora 10 (and EPEL), %{_buildrootdir} does not exist.
Build flags macros

%{_global_cflags}     -O2 -g -pipe
%{_optflags}          %{__global_cflags} -m32 -march=i386 -mtune=pentium4 # if redhat-rpm-config is installed  

3.4 %build段

本段是建立段,所要執行的命令為生成軟體包服務,如make 命令。 這一節一般由多個make命令組成。與 Prep段落一樣,這些命令可以是 shell 命令,也可以是巨集。

3.5 %install段

本段是安裝段,其中的命令在安裝軟體包時將執行,類似make install命令。有些spec檔案還有%post-install段,用於定義在軟體安裝完成後的所需執行的配置工作。

這個段落用於將已編譯的軟體安裝到虛擬的目錄結構中,從而可以打包成一個 RPM。這個很重要,因為如果這裡的路徑不對的話,則下面%file中尋找檔案的時候就會失敗

%makeinstall 這不是關鍵字,而是rpm定義的標準巨集命令

3.6 %files段

本段是檔案段,用於定義軟體包所包含的檔案,分為三類–說明文件(doc),配置檔案(config)及執行程式,還可定義檔案存取許可權,擁有者及組別。

這裡會在虛擬根目錄下進行,千萬不要寫絕對路徑,而應用巨集或變數表示相對路徑。 如果描述為目錄,表示目錄中除%exclude外的所有檔案。%defattr (-,root,root) 指定包裝檔案的屬性,分別是(mode,owner,group),-表示預設值,對文字檔案是0644,可執行檔案是0755

3.7 %clean

※注意區分$RPM_BUILD_ROOT$RPM_BUILD_DIR
$RPM_BUILD_ROOT是指開頭定義的BuildRoot,而$RPM_BUILD_DIR通常就是指/usr/src/asianux/BUILD

3.8 %exclude

%exclude 列出不想打包到rpm中的檔案
※小心,如果%exclude指定的檔案不存在,也會出錯的。

3.9 %changelog段

本段是修改日誌段。你可以將軟體的每次修改記錄到這裡,儲存到釋出的軟體包中,以便查詢之用。每一個修改日誌都有這樣一種格式:第一行是:* 星期 月 日 年 修改人 電子信箱。其中:星期、月份均用英文形式的前3個字母,用中文會報錯。接下來的行寫的是修改了什麼地方,可寫多行。一般以減號開始,便於後續的查閱。

四、打包

如果想釋出rpm格式的原始碼包或者是二進位制包,就要使用rpmbuild工具(rpm最新打包工具)。如果我們已經根據本地原始碼包的成功編譯安裝而寫了spec檔案(該檔案要以.spec結束),那我們就可以建立一個打包環境,也就是目錄樹的建立,一般是在/usr/src/redhat/目錄下建立5個目錄。它門分別是BUILD、SOURCE、SPEC、SRPM、RPM。

  • BUILD目錄用來存放打包過程中的原始檔,
  • SOURCE用來存放打包是要用到的原始檔和patch,
  • SPEC用來存放spec檔案,
  • SRPM、RPM分別存放打包生成的rpm格式的原始檔和二進位制檔案。當然我們可以根據需要來選用不同的引數打包檔案,筆者總結如下3條。

1) 只生成二進位制格式的rpm包

rpmbuild -bb xxx.spec

用此命令生成軟體包,生成的檔案會在剛才建立的RPM目錄下存在。

2)只生成src格式的rpm包

rpmbuild -bs xxx.spec

生成的檔案會在剛才建立的SRPM目錄下存在。

3) 只需要生成完整的原始檔

rpmbuild -bp xxx.spec

原始檔存在目錄BUILD下。可能對這個命令不太明白,這個命令的作用就是把tar包解開然後把所有的補丁檔案合併而生成一個完整的具最新功能的原始檔。

4) 完全打包

rpmbuild -ba xxx.spec

軟體包製作完成後可用rpm命令查詢,看看效果。如果不滿意的話可以再次修改軟體包描述檔案,重新執行以上命令產生新的RPM軟體包。

五、示例

因為rpm只認tar.gz格式,所以,必須打包好並移動到SOURCES目錄中

5.1 準備

RPM打包使用的是rpmbuild命令,來自prm-build包:

yum install rpm-build

也可以安裝rpmdevtools,這個工具部包含一些其他工具,依賴rpm-build,所以直接安裝會將rpm-build裝上:

yum install rpmdevtools

python的編譯打包工具是setuptools

5.2 原理

rpmbuild命令使用一套標準化的“工作空間”:

rpmdev-setuptree

rpmdev-setuptree這個命令就是安裝rpmdevtools帶來的。可以看到執行了這個命令之後,在$HOME家目錄下多了一個叫做rpmbuild的資料夾,裡邊內容如下:

$ tree rpmbuild
rpmbuild
├── BUILD
├── RPMS
├── SOURCES
├── SPECS
└── SRPMS

如果沒有安裝rpmdevtools的話,其實用mkdir命令建立這些資料夾也是可以的:mkdir -p ~/rpmbuild/{BUILD,RPMS,SOURCES,SPECS,SRPMS}

預設位置 巨集程式碼 名稱 用途
~/rpmbuild/SPECS %_specdir Spec 檔案目錄 儲存 RPM 包配置(.spec)檔案
~/rpmbuild/SOURCES %_sourcedir 原始碼目錄 儲存原始碼包(如 .tar 包)和所有 patch 補丁
~/rpmbuild/BUILD %_builddir 構建目錄 原始碼包被解壓至此,並在該目錄的子目錄完成編譯
~/rpmbuild/BUILDROOT %_buildrootdir 最終安裝目錄 儲存 %install 階段安裝的檔案
~/rpmbuild/RPMS %_rpmdir 標準 RPM 包目錄 生成/儲存二進位制 RPM 包
~/rpmbuild/SRPMS %_srcrpmdir 原始碼 RPM 包目錄 生成/儲存原始碼 RPM 包(SRPM)

5.3 下載原始碼

cd ~/rpmbuild/SOURCES
wget http://ftp.gnu.org/gnu/hello/hello-2.10.tar.gz

5.4 編輯SPEC檔案

cd ~/rpmbuild/SPECS
vim hello.spec

開啟發現已經有一些模版了,填入:

Name:     hello
Version:  2.10
Release:  1%{?dist}
Summary:  The "Hello World" program from GNU
Summary(zh_CN):  GNU "Hello World" 程式
License:  GPLv3+
URL:      http://ftp.gnu.org/gnu/hello
Source0:  http://ftp.gnu.org/gnu/hello/%{name}-%{version}.tar.gz

BuildRequires:  gettext
Requires(post): info
Requires(preun): info

%description
The "Hello World" program, done with all bells and whistles of a proper FOSS
project, including configuration, build, internationalization, help files, etc.

%description -l zh_CN
"Hello World" 程式, 包含 FOSS 專案所需的所有部分, 包括配置, 構建, 國際化, 幫助檔案等.

%prep
%setup -q

%build
%configure
make %{?_smp_mflags}

%install
make install DESTDIR=%{buildroot}
%find_lang %{name}
rm -f %{buildroot}/%{_infodir}/dir

%post
/sbin/install-info %{_infodir}/%{name}.info %{_infodir}/dir || :

%preun
if [ $1 = 0 ] ; then
/sbin/install-info --delete %{_infodir}/%{name}.info %{_infodir}/dir || :
fi

%files -f %{name}.lang
%doc AUTHORS ChangeLog NEWS README THANKS TODO
%license COPYING
%{_mandir}/man1/hello.1.*
%{_infodir}/hello.info.*
%{_bindir}/hello

%changelog
* Sun Dec 4 2016 Your Name <youremail@xxx.xxx> - 2.10-1
- Update to 2.10
* Sat Dec 3 2016 Your Name <youremail@xxx.xxx> - 2.9-1
- Update to 2.9

Group標籤過去用於按照 /usr/share/doc/rpm-/GROUPS 分類軟體包。目前該標記已丟棄,vim的模板還有這一條,刪掉即可,不過新增該標記也不會有任何影響。

5.5 構建RPM包

rpmbuild -ba hello.spec

OK,執行成功,看看結果:

$ tree ~/rpmbuild/*RPMS
/root/rpmbuild/RPMS
└── x86_64
    ├── hello-2.10-1.el7.centos.x86_64.rpm
    └── hello-debuginfo-2.10-1.el7.centos.x86_64.rpm
/root/rpmbuild/SRPMS
└── hello-2.10-1.el7.centos.src.rpm

5.6 安裝RPM包

rpm -ivh ~/rpmbuild/RPMS/x86_64/hello-2.10-1.el7.centos.x86_64.rpm 

執行:

$ hello
Hello, world!
$ which hello
/usr/bin/hello
$ rpm -qf `which hello`
hello-2.10-1.el7.centos.x86_64
man hello

小結

看了以上SPEC的總結,以為了解差不多了,結果看了網路域的SPEC檔案,自己真實too young too simple。看看能否看懂吧:fn-venv-python-common-packages-arm

參考