在不具備 root 權限的情況下構建、給軟件打補丁和分發 RPM
Dan Poirier(
[email protected])
軟件工程師,IBM
2001 年 12 月
RPM 是一種廣泛用於發布 Linux 軟件的工具;用戶可以輕松地安裝用 RPM 打包的產品。 在本文(該系列文章的第 2 篇)中,Dan 說明了在不具備 root 權限的情況下如何對軟件進行打包,在不做更改的情況下如何處理不在 Linux 上構建的軟件,以及如何分發您的工作結果。
如果您沒有閱讀過本系列文章的第 1 部分, 那麼您可能希望在繼續閱讀本文之前先閱讀那篇文章。
不作為 root 用戶來構建 RPM 包
正如您在第 1 部分中看到的那樣,構建 RPM 軟件包通常要求您以 root 用戶登錄。 其原因如下:
1. RPM 在打包過程中安裝軟件,並且通常只有 root 用戶可以寫到安裝目錄中。
2. RPM 需要讀寫 /usr/src/redhat(一般用戶不能修改它)下的目錄。
我們在第 1 部分中探討了通過用 RPM 構建根(build root)來解決第一個問題。
要解決第二個問題,可以通過更改 %_topdir 設置來告訴 RPM 查找和創建不同目錄集中的文件。按照下面的方法在您的主目錄下創建一個名為 .rpmmacros的文件:
%_topdir /home/your_userid/rpm
這個文件會告訴 RPM:它先前在 /usr/src/redhat 下查找的所有目錄應該改為在 /home/your_userid/rpm 下查找。 現在,您應該創建這樣一個完整的目錄樹:
~/rpm
~/rpm/SOURCES
~/rpm/SPECS
~/rpm/BUILD
~/rpm/RPMS
~/rpm/RPMS/i386
~/rpm/SRPMS
(如果願意,可以通過在 RPM 中重新定義其它宏,來將其中任何目錄放在您想放的任何地方。您可能需要考慮更改的一些宏包括 %_sourcedir、%_specdir、%_srcrpmdir、%_builddir 和 %_rpmdir。 有關這些宏的缺省值,請查看 /usr/lib/rpm/macros。 對於這個示例,我們僅僅將它們都放在 ~/rpm 下。)
現在,將 indent-2.2.6.tar.gz 文件(請參閱本文後面的參考資料)復制到 ~/rpm/SOURCES,這裡沒有以 root 用戶登錄,運行 rpm -ba indent-2.spec(這些文件就是第 1 部分中的那些文件)。RPM 將 把 indent 構建在 ~/rpm/BUILD 目錄下,並將二進制的 RPM 包放在 ~/rpm/RPMS/i386 中,將源代碼包放在 ~/rpm/SRPMS 中。
與之相對照,在沒有構建根的情況下,嘗試使用 spec 文件 indent-1.spec。RPM 在嘗試將 indent 安裝到 /usr/local/bin 中時會失敗。
告誡
使用構建根和設置 RPM 的 i%_topdir 使您能在不作為 root 運行的情況下構建許多軟件包,但這並不總是很容易。
首先,一些包並不象 indent 那樣可以容易地安裝到構建根目錄中。對於那些任何未用 GNU autoconf 來開發的包,您必須要仔細查看一下,看是否有一種方法,可以將包安裝到另一個目錄中, 這也許可以修改 Makefile 來強制這樣做。在下一部分中,我將向您演示如何使用 RPM 來構建已修改的程序。
其次,只有相當少部分包將在其正常安裝期間試圖做一些只有 root 用戶才可以做的事情,如:
* 創建特殊文件(管道、設備文件等等)
* 修改系統配置文件`
您必須逐個處理這些問題。通常,您可以在 post-install 腳本(在安裝 RPM 之後運行的腳本)中做一些必要工作。我將在以後的文章中討論它們,但簡而言之,可以將“%post”節添加到 spec 文件中, 並在該節中放置一些 Linux 命令,以便在安裝 RPM 之後運行這些命令。
給軟件打補丁
假設您有一些要打成 RPM 包的軟件, 但如果不對它做一些更改,就不能在 Linux 上構建它。 然而,您又沒有擁有該軟件,所以不能正式地更改它。
您所需要做的就是對該軟件的正式版本進行打補丁或做一些修改。 但是,對其他人的軟件進行修改,然後再分發此修改過的版本通常被認為是不禮貌的,所以您希望您自己所做的更改對別人來說也是可用的。 這樣,使用您的包的任何人都可以看到您做了哪些事情以及確定您所做的更改是否是可接受的。
這是常有的事,而且 RPM 也提供一些幫助。 您可以建立一個 RPM 包,以便二進制 RPM 文件包含您對程序所做的修改,並且源 RPM 不僅包含原始的源代碼, 而且還包含您所做的更改以及有關如何應用和構建這些更改的所有詳細信息。
這些步驟如下:
1. 斷定對源代碼做哪些更改就可使軟件工作。
2. 創建一個補丁文件來捕獲您所做的更改。
3. 將該補丁添加到 RPM spec 文件。
第 1 步. 斷定要對源代碼做哪些更改
通常,要做的第一件事是,在沒有 RPM 的情況下編譯並運行軟件。明了必須要更改的那些文件。 如果有必要,可創建一些新文件或除去與原始源代碼一起交付的一些文件。
對於這個示例,我將代碼抽取到目錄 indent-2.2.6-working 中。我修改了 indent.c, 以便在程序啟動時打印一條表示友好的消息,然後驗證該程序是否仍可以構建以及該程序是否仍能工作。
第 2 步. 創建補丁文件來捕獲您所做的更改
現在,您希望創建一個僅捕獲您所做更改的補丁文件。 這裡有一種可以實現這的方法。雖然這有點兒乏味,但能夠確保您捕獲所有更改。
1. 將軟件完全抽取到一個新目錄中,然後復制您已對其做過更改的文件,使其覆蓋剛抽取出的那些文件。 這樣,在本來應該在您先前構建和測試軟件時創建的目錄中就不會有任何多余的文件。 類似地,復制您創建的任何新文件,並刪除任何您先前刪除過的文件。
對於這個示例,我已完全抽取到目錄 indent-2.2.6-my,並覆蓋文件 indent.c。
2. 再一次將軟件抽取到另一個目錄。這樣就提供了一個原始軟件的副本來與您的軟件進行比較。對於這個示例,我是將軟件抽取到 indent-2.2.6 目錄。
現在,已有三個目錄:
indent-2.2.6-working
工作目錄
indent-2.2.6-my
經過更改的軟件,其中含有我所做的更改
indent-2.2.6
未更改的軟件
3. 從這三個目錄的父目錄中用類似於以下的命令生成補丁文件:
diff -uNr indent-2.2.6 indent-2.2.6-my >indent-2.2.6.patch
注意,使用 diff 時運用了選項 -uNr。-u 以統一格式創建補丁文件,這種格式比缺省格式更緊湊些。-N 確保補丁文件將正確地處理已經創建或刪除文件的情況。-r 比較命令行上所給出的兩個目錄的所有子目錄中的所有文件。
另外還要注意:只要您完全按上述來做,這些目錄名是無關緊要的。 補丁文件中將有這些目錄名,但我們將通知補丁程序忽略它們。
現在,檢查一下補丁文件 indent-2.2.6.patch。下面是我的示例:
清單 1. indent-2.2.6.patch
diff -uNr indent-2.2.6/indent.c indent-2.2.6-my/indent.c
--- indent-2.2.6/indent.c Thu Nov 16 22:01:04 2000
+++ indent-2.2.6-my/indent.c Wed Sep 26 14:33:11 2001
@@ -1864,6 +1864,8 @@
int using_stdin = false;
enum exit_values exit_status;
+ printf("Hello from Dan
");
+
#ifdef _WIN32
/* wildcard eXPansion of commandline arguments, see wildexp.c */
extern void wildexp (int *argc, char ***argv);
有時候,您會注意到 diff 檢查出了您無意要做的更改。 這時,您可能需要回過去,清除您的代碼並再次生成補丁,直到獲得一個干淨的、令您滿意的補丁文件為止。
一旦按您所希望的那種方式完成補丁之後,最好添加注釋以說明您所做的更改。 在不損害任何內容的情況下,在補丁文件的開始處或結束處添加文本。
清單 2. 帶注釋的 indent-2.2.6.patch
Dan Poirier - 2001-09-26 - added a friendly greeting as indent starts.
This is just an example.
diff -uNr indent-2.2.6/indent.c indent-2.2.6-my/indent.c
--- indent-2.2.6/indent.c Thu Nov 16 22:01:04 2000
+++ indent-2.2.6-my/indent.c Wed Sep 26 14:33:11 2001
@@ -1864,6 +1864,8 @@
int using_stdin = false;
enum exit_values exit_status;
+ printf("Hello from Dan
");
+
#ifdef _WIN32
/* wildcard expansion of commandline arguments, see wildexp.c */
extern void wildexp (int *argc, char ***argv);
第 3 步. 將該補丁添加到 RPM spec 文件中
現在,該讓 RPM 使用您的補丁了。將該補丁文件復制到您的 SOURCES 目錄(如果您遵循了先前的建議,則或許是 ~/rpm/SOURCES),然後對 spec 文件做下列更改:
清單 3. indent-3.spec:使用 indent-2.2.6.patch
Summary: GNU indent
Name: indent
Version: 2.2.6
Release: 3
Source0: %{name}-%{version}.tar.gz
Patch0: %{name}-2.2.6.patch
License: GPL
Group: Development/Tools
BuildRoot: %{_builddir}/%{name}-root
%description
The GNU indent program reformats C code to any of a variety of
formatting standards, or you can define your own.
%prep
%setup -q
%patch -p1
%build
./configure
make
%install
rm -rf $RPM_BUILD_ROOT
make DESTDIR=$RPM_BUILD_ROOT install
%clean
rm -rf $RPM_BUILD_ROOT
%files
%defattr(-,root,root)
/usr/local/bin/indent
%doc /usr/local/info/indent.info
%doc %attr(0444,root,root) /usr/local/man/man1/indent.1
%doc COPYING AUTHORS README NEWS
現在,用 rpm -ba indent-3.spec 命令構建您的包。 如果您密切關注構建過程的話,會看到在構建期間 RPM 應用了您的補丁。
%Patch0: %{name}-2.2.6.patch 這一行告訴 RPM 第一個補丁文件名。 如果有必要,可以添加 %Patch1、%Patch2 等。
在 %prep 部分中的 %patch -p1 行是一個 RPM 宏, 它將在您系統的構建目錄中運行補丁程序,其中把第一個補丁文件作為輸入。 需要將 -p1 傳遞給補丁程序,告訴它從補丁文件中的路徑中剝去一層目錄,因為該補丁文件包含 indent-2.2.6 目錄名,而 RPM 將在該目錄內運行該補丁文件。
通過示例學習
既然,您理解了有關如何構建 RPM 包的基礎知識,則可以通過研究一些示例來學習更多的知識。 最好的源代碼示例之一是您自己的 Linux 分發版。例如,RedHat 帶有包含源 RPM 包的整張 CD。 以下是如何使用它們。
源 RPM 包包含:
* 一個 .spec 文件
* 一個或多個源文件
* 所有使用過的補丁文件
與安裝二進制 RPM 包類似,可以使用 rpm -i filename.rpm 安裝源 RPM 包。 安裝完之後,.spec 文件將在您的 %_specdir 目錄中,源文件和補丁文件將在您的 %_sourcedir 目錄中。 如果創建了上面描述的 .rpmmacros 文件,那麼這些目錄為 ~/rpm/SPECS 和 ~/rpm/SOURCES。
現在,可以讀取 Red Hat 自己分發的這些包的 .spec 文件。 可以嘗試用 rpm -ba foo.spec 構建這些 .spec 文件,並觀察所發生的事情,以及擺弄 spec 文件以嘗試一些新的事物。
對於 GNU indent 程序,一個好的方法是從 Red Hat 的源 RPM 包開始。看一下您是否可以想出為什麼它們的 .spec 文件不同於本文中的 .spec 文件。
二進制 RPM 包的可移植性
不幸的是,二進制 RPM 包在可移植性方面不是很好。多數情況下,構建在某個 Linux 分發版上的 RPM 不能應用到另一個 Linux 分發版。 更不要說應用到同一個分發版的另一個版本上!
原因有很多,包括基本內核版本、庫版本和目錄結構方面的差異。
這很不幸,但象 Linux Standard Base(請參閱參考資料)這樣的組織正在嘗試達到分發版之間的一致, 以解決難以移植的問題。也許有一天,構建在一個主流 Linux 分發版上的任何 RPM 都可以安裝和運行在相同的處理器之上的任何 其它主流 Linux 分發版上。
至於現在,您應該做好計劃,有多少個 RPM 將要在其上運行的分發版,就可能構建有多少個 RPM,或者尋找志願者來為您完成這件事。
分發您的工作結果:tar 文件和源 RPM 包
為了使其他人在盡可能多的分發版上構建您的軟件,就要使 .spec 文件和補丁文件成為可用的文件。
如果有必要,最好的方法是直接更改軟件,所以該方法將在 Linux 上進行構建,並將 .spec 文件包含在分發版中。 如果 .spec 文件在帶有源碼的 tar 壓縮包(.tar.gz 文件)中,那麼用戶只需運行:
rpm -tb foo.tar.gz
並構建該包的二進制 RPM — 甚至無需解壓該 tar 文件!
如果無法使 .spec 文件包含在軟件中,則可以分發一個源 RPM 包。 有了這,用戶就可以運行:
rpm --rebuild foo.src.rpm
並在他們的系統上構建二進制 RPM。
參考資料
* 本系列的先前文章介紹了用 RPM 構建軟件包的過程。
* 本文中描述的文件源代碼:
o indent-2.2.6.patch
o 帶注釋的 indent-2.2.6.patch
o indent-3.spec
* RPM 網站上有指向許多有用資源的鏈接。RPM 電子郵件列表是提問題的好地方。
* Maximum RPM 是一本關於使用 RPM 的書。它相當過時了,但現在正處在更新中。
* RPM HOWTO 也正變得有些過時了。它講述了一些和本文一樣的知識范圍。
* Eric S. Raymond 的 Software Release Practice HOWTO 文檔並不是專門針對 RPM 或 Linux。但它在如何發布軟件以方便用戶使用和方便程序員提供補丁和完善方面,有很多好的技巧。
* 請閱讀 Linux Standard Base(LSB),它的目的是要“開發和提倡一組標准, 以增加 Linux 分發版之間的兼容性並使軟件應用程序能夠運行在任何兼容的 Linux 系統上。”
* 自由軟件基金會(The Free Software Foundation)是一個提供 GNU Indent 和許多其它有用軟件包的組織。
* 請獲取 IBM Developer Kit for Linux on Itanium、IBM Developer Kit for Linux,Java 2 版,版本 1.3 或者 IBM Software Evaluation Kit for Linux。
* 請在 developerWorks 上浏覽更多 Linux 參考資料。
* 請在 developerWorks 上浏覽更多開放源碼參考資料。
關於作者
Dan Poirier 是 IBM 的顧問軟件工程師。他目前在美國北卡羅萊納州的 Research Triangle Park 工作,從事運行 Linux 的網絡設備的研究。可以通過
[email protected] 與他聯系
來自:www-900.ibm.com