使用 RPM 打包軟件,第 1 部分: 構建和分發包

顧名思義,開源軟件的主要優勢就是允許瞭解應用程序的內部工作原理。有了源代碼,您可以研究應用程序的工作原理,更改、改進和擴展其操作,(在應用程序許可允許下)借鑑代碼並將其用於其他用途,以及將應用程序移植到新平臺上。

然而,這種自由訪問並不總是我們所需要的。例如,用戶可能不希望從源代碼進行構建。相反,他或她可能只想像傳統 “緊湊包裝” 的應用程序一樣安裝該軟件:插入媒體、運行安裝程序、回答一系列提示,然後運行應用程序。確實,對於大部分計算機用戶來說,這種預構建的軟件是他們最希望得到的。預構建代碼對系統特性不那麼敏感,因此更統一且可預測。

通常,預構建的開源應用程序稱爲,捆綁了運行應用程序所需的所有二進制文件、數據和配置文件。包還包括將應用程序部署到系統上所需的所有步驟,這些步驟通常以腳本形式提供。腳本可以生成數據,啓動和停止系統服務,或者操作文件和目錄。腳本還可以執行操作來將現有軟件升級到新版本。

由於每個操作系統都具有自己的獨特特性,所以包通常僅適用於特定系統。而且,每個操作系統提供了自己的包管理器,一個用於在系統中添加和刪除包的特殊實用程序。例如,基於 Debian Linux® 的系統使用 Advanced Package Tool (APT),而 Fedora Linux 系統使用 RPM Package Manager。包管理器通過添加和刪除包中的各個文件來來預防不完整和錯誤的安裝,以及 “卸載” 應用程序。包管理器還維護着系統上安裝的所有包的清單,可以預先檢查前提條件和輔助條件是否滿足。

如果您是一名軟件開發人員或系統管理員,以包的形式提供應用程序可以使安裝、升級和維護更加輕鬆。在本文中,您將瞭解到如何使用流行的 RPM Package Manager 捆綁實用程序。作爲演示,您將捆綁網絡實用程序 wget,該程序用於從 Internet 下載文件。wget 實用程序很有用,但在標準的系統分發版中很難找到它。(而類似的 curl 通常包含在系統分發版中。)您將發現,您可以使用 RPM 分發幾乎所有內容(腳本、文檔和數據),以及執行幾乎所有維護任務。

手動構建 wget

wget 實用程序,與其他許多開源應用程序一樣,可以手動構建。要將 wget 捆綁在一個包中,首先需要了解構建過程。根據一般約定,構建 wget 需要 4 個步驟:

  1. 下載並解壓源代碼。
  2. 配置構建版本。
  3. 編譯代碼。
  4. 安裝軟件。

您可以從 ftp.gnu.org 下載 wget 源代碼的最新版本(參見 參考資料 獲取鏈接,截至 2009 年 9 月末,wget 的最新版本爲 1.12)。其餘步驟需要在命令行操作,如 清單 1 所示。


清單 1. 安裝 wget
				
$ tar xzf wget-latest.tar.gz
$ cd wget-1.12
$ ./configure
configure: configuring for GNU Wget 1.12
checking for a BSD-compatible install... /usr/bin/install -c
checking whether build environment is sane... yes
checking for a thread-safe mkdir -p... build-aux/install-sh -c -d
checking for gawk... no
checking for mawk... no
checking for nawk... no
...
$ make
$ sudo make install

./configure 查詢系統並設置適合於所選硬件和軟件的編輯選項。make 編譯代碼,sudo make install 在系統目錄中安裝代碼。默認情況下,安裝的根目錄爲 /usr/local,但您可以對 ./configure 使用 --prefix=/some/full/path/name 選項來更改根目錄。

要將此過程轉換爲 RPM,將源代碼放在存儲庫中,編寫一個配置文件來說明可在哪裏找到要編譯的源代碼以及如何編譯和安裝代碼。配置文件稱爲 spec 文件,是實用程序 rpmbuild 的輸入。spec 文件和二進制文件被 rpmbuild 打包到一個 RPM 中。當其他用戶下載您的 RPM 時,rpm 實用程序讀取 spec 文件並根據預先編寫的指令安裝包。

構建您的第一個 RPM

在繼續之前,需要注意一點。在過去,包只能由根用戶和超級用戶構建,因爲只有根用戶才能訪問系統源代碼庫。但是,此方法具有一定的冒險性。因爲根用戶可以更改系統上的任何文件,它可以在臨時構建 RPM 期間隨意添加外部文件或刪除重要文件,從而更改正在運行的系統。最近,RPM 系統經過了更改,允許任何用戶在主目錄中構建 RPM。不需要根用戶特權就能構建 RPM,這可以阻止更改核心系統文件。下面介紹了這種更加現代的方法。

要構建 RPM,必須:

  • 依照 rpmbuild 規範設定一個目錄結構。
  • 將源代碼和附帶文件放在目錄中合適的位置。
  • 創建 spec 文件。
  • 編譯 RPM。可以選擇編譯源 RPM,以與其他人共享您的源代碼。

首先,構建目錄。在主目錄下的一個子目錄中,假設爲 $HOME/mywget,創建 5 個子目錄:

  • BUILD。BUILD 用作實際編譯軟件的暫存空間。
  • RPMS。RPMS 包含 rpmbuild 所編譯的二進制 RPM。
  • SOURCES。SOURCES 存儲源代碼。
  • SPECS。SPECS 包含您的 spec 文件,您想要構建的一個 RPM 對應一個 spec 文件。
  • SRPMS。SRPMS 包含在這個過程中構建的源 RPM。

您至少需要 SOURCES 中的源代碼和 SPEC 中的一個 spec 文件。

將源代碼(理想情況下應捆綁爲一個 tarball 壓縮文件)複製到 SOURCES 目錄,如 清單 2 所示。如果有必要,重命名 tarball 壓縮文件,以包含應用程序的版本號,便於與其他文件區分開。約定的命名格式爲包-版本.tar.gz。對於 wget,您可以使用:


清單 2. 複製源代碼
				
$ cd ~
$ mkdir mywget
$ cd mywget 
$ mkdir BUILD RPMS SOURCES SPECS SRPMS
$ cd SOURCES
$ cp wget-latest.tar.gz .
$ mv wget-latest.tar.gz wget-1.12.tar.gz
$ cd ..

接下來,創建 spec 文件。spec 文件只是一個具有特殊語法的文本文件。清單 3 給出了一個 spec 文件的例子。


清單 3. 示例 spec 文件
				
# This is a sample spec file for wget

%define _topdir	 	/home/strike/mywget
%define name			wget 
%define release		1
%define version 	1.12
%define buildroot %{_topdir}/%{name}-%{version}-root

BuildRoot:	%{buildroot}
Summary: 		GNU wget
License: 		GPL
Name: 			%{name}
Version: 		%{version}
Release: 		%{release}
Source: 		%{name}-%{version}.tar.gz
Prefix: 		/usr
Group: 			Development/Tools

%description
The GNU wget program downloads files from the Internet using the command-line.

%prep
%setup -q

%build
./configure
make

%install
make install prefix=$RPM_BUILD_ROOT/usr

%files
%defattr(-,root,root)
/usr/local/bin/wget

%doc %attr(0444,root,root) /usr/local/share/man/man1/wget.1

我們從頭到尾分析一下這個 spec 文件。第 1-5 行定義在文件其餘部分中使用的快捷變量。第 7-15 行使用 參數: 值 的形式設置若干個必需的參數。在第 7 行或其他地方可以看到,變量可以進行計算和組合,以生成某個設置的值。

大部分參數的名稱都不言自明,但需要對 BuildRoot 稍作說明,以將其與已創建的 BUILD 目錄路區分開。BuildRoot 代表最終的安裝目錄。換言之,如果 wget 最終安裝在 /usr/local/bin/wget 和 /usr/local 中的其他子目錄下,比如文檔安裝在 /usr/local/man 下,那麼在 RPM 構建過程中 BuildRoot 代表 /usr/local。一旦設定了 BuildRoot,就可以使用 RPM_BUILD_ROOT 環境變量訪問其值。應該始終在 spec 文件中設置 BuildRoot 並檢查該目錄的內容,確認包即將安裝的內容。

下面有一些技巧:

  • 不要使用 ./configure --prefix=$RPM_BUILD_ROOT。此命令構建整個包,假定文件的最終位置爲構建根目錄。這可能導致需要在運行時定位其已安裝文件的程序發生故障,因爲當 RPM 最終安裝在用戶系統上時,安裝的文件不再位於構建根目錄下,該目錄只是您的構建系統上的一個臨時目錄。
  • 不要在 Source 的定義中包含路徑。
  • 主版本和次版本很重要。每次更改應用程序的代碼或數據,以及構建好一個新 RPM 時,一定要增加主版本和次版本的值,以分別反映主要和次要的更改。您會發現每次構建一個 RPM 時就增加版本編號對於將每次修改嘗試都分開很有用,即使是供您自己使用。

下一節代碼首先是一個 %description。您應該在這裏簡單明瞭地描述軟件。這一行將在用戶運行 rpm -qi 來查詢 RPM 數據庫時顯示。您可以說明包的用途,描述任何警告或額外的配置說明等。

接下來依次是 %prep%build 和 %install 節。每一節生成一個 shell 腳本,該腳本嵌入到 RPM 中,隨後作爲安裝的一部分運行。%prep 準備源代碼,比如解壓 tarball 壓縮文件。在這裏,%setup -q 是一個 %prep 宏,用於自動解壓 Source 中的特定 tarball 壓縮文件。

您應該熟悉 %build 節中的指令。它們相當於用於手動配置和啓動構建過程的步驟。%install 節也是如此。但是,儘管手動構建的目標目錄是系統上的 /usr/local 目錄,但 %install 指令的目標目錄爲 ~/mywget/BUILD。

%files 列出應該捆綁到 RPM 中的文件,還可以設置權限和其他信息。在 %files 內,您可以使用 %defattr 宏定義默認權限、所有者和 RPM 中的文件分組。在本例中,%defattr(-,root,root) 安裝根用戶擁有的所有文件,使用 RPM 從構建系統捆綁這些文件時找到的權限。

在 %files 中,可以在一行中包含多個文件。可以將 %doc 或 %config 添加到該行,以標記文件。%doc 告訴 RPM 該文件爲一個文檔文件,所以如果用戶使用 --excludedocs 安裝包,將不會安裝該文件。%config 告訴 RPM 這是一個配置文件。在升級期間,RPM 將嘗試避免使用 RPM 打包的默認配置文件覆蓋用戶小心修改的配置。

請注意,如果在 %files 下列出一個目錄名稱,RPM 將包含該目錄下的每個文件。

構建 RPM

現在您的文件已經就緒,spec 文件也已經定義了,接下來就可以構建實際的 RPM 文件了。要構建它,使用適當命名的 rpmbuild 實用程序:

$ rpmbuild -v -bb --clean SPECS/wget.spec

此命令使用指定的 spec 文件構建一個二進制包(-bb 表示 “構建二進制包”),還會生成詳細的輸出(-v)。構建實用程序在生成包之後刪除構建樹(--clean)。如果還希望構建源 RPM,指定 -ba(“構建所有包”)來代替 -bb。(查看 rpmbuild 清單頁面,瞭解完整的選項列表。)

rpmbuild 執行以下步驟:

  • 讀取並解析 wget.spec 文件。
  • 運行 %prep 節,將源代碼解壓到臨時目錄。在這裏,臨時目錄爲 BUILD。
  • 運行 %build 節,編譯代碼。
  • 運行 %install 節,將代碼安裝到構建機器上的目錄中。
  • 從 %files 節讀取文件列表,將它們收集到一起,然後創建一個二進制 RPM(和源 RPM 文件,如果已選擇)。

如果查看 $HOME/mywget 目錄,應該找到一個名爲 wget-1.12-root 的新目錄,此目錄表示目標目錄。還應該找到一個名爲 RPMS/i386 的新目錄,而且它應該包含您的 RPM,名爲 wget-1.12-1.i386.rpm。RPM 的名稱表明這是針對 i386 處理器的 wgetversion 1.12。

要驗證 RPM 是否包含合適的文件,可以使用 rpm 命令,如 清單 4 所示。


清單 4. 驗證 RPM 內容
				
$ rpm -Vp RPMS/i386/wget-1.12-1.i386.rpm
missing     /usr/local/bin/wget
.M....G.    /usr/local/etc
missing   c /usr/local/etc/wgetrc
.M....G.    /usr/local/share
missing     /usr/local/share/info
missing   d /usr/local/share/info/wget.info
missing     /usr/local/share/locale
missing     /usr/local/share/locale/be
missing     /usr/local/share/locale/be/LC_MESSAGES
missing   d /usr/local/share/locale/be/LC_MESSAGES/wget.mo
.
.
.

命令 rpm -Vp RPMS/i386/wget-1.12-1.i386.rpm 驗證包是否包含系統中的文件。儘管似乎存在很多錯誤,但每個錯誤都暗示了 RPM 文件的內容是正確的。如果您希望安裝某個文件,而該文件未出現在輸出中,則說明它未包含在包中。在這種情況下,請查看 spec 文件,確保該文件已在 %files 節中列出。

驗證了 RPM 之後,可以將文件分發給同事。同事收到文件之後,應該可以運行 rpm 來在其自己的系統上安裝 wget

$ sudo rpm -i wget-1.12-1.i386.rpm

RPM 的其他用途

這篇簡短介紹文章只觸及了 RPM 的用途的表面。儘管它最常用於安裝軟件和附帶文件,但您幾乎可以打包任何內容,從系統腳本到源代碼到文檔。在本系列第二期中您將會看到,還可以使用 RPM 修補源代碼,以及重新構建和重新安裝軟件。RPM 分發格式可以在許多 Linux 系統上找到,是在 Red Hat 和 Fedora 等系統中安裝二進制軟件的首選方法。

如果您使用 RPM 構建和打包軟件,那麼也將能夠體驗到 RPM 的這些其他用途。

發佈了170 篇原創文章 · 獲贊 1 · 訪問量 1萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章