創建軟件包
本文旨在幫助用户利用類似於 ports 軟件的 Arch 構建系統來創建自己的軟件包,這些軟件包可以提交到 Arch 用户軟件倉庫 (AUR)。本文講述了如何創建 PKGBUILD(5),這是一個描述如何構建軟件包的文件,makepkg 會使用它來從原始碼創建二進制軟件包。Arch 軟件包標準中有一些構建規則和提高軟件包質量的方法。
概述[編輯 | 編輯原始碼]
Arch Linux 中的軟件包是通過 makepkg 工具以及存儲在 PKGBUILD
文件中的信息編譯的。運行 makepkg 時,系統將自動在當前目錄下搜索 PKGBUILD
文件,然後根據 PKGBUILD
把軟件源碼重新打包。成功編譯後得到的二進制文件和可以得到的其他信息如包的版本信息和依賴關係等,都將被打包到一個文件叫pkgname.pkg.tar.zst
裡,可以通過 pacman 進行安裝。
一個 Arch 軟件包就是一個使用 zstd(1) 壓縮的 tar(1) 壓縮包,或者叫 tarball 。它包含了以下由 makepkg 生成的文件:
- 要安裝的二進制文件;
.PKGINFO
: 包含所有 pacman 處理軟件包的元數據,依賴等等;
.BUILDINFO
: 包含可復現編譯需要的信息,參閱 BUILDINFO(5) ;
.MTREE
: 包含了文件的哈希值與時間戳,pacman 能夠根據這些儲存在本地數據庫的信息校驗軟件包的完整性;
.INSTALL
: 可選的文件,可以用來在安裝/升級/刪除操作之後運行命令。(本文件只有在PKGBUILD
中制定才會存在);
.Changelog
: 一個可選的文件,保存了包管理員描述軟件更新的日誌。
準備工作[編輯 | 編輯原始碼]
必需的軟件包[編輯 | 編輯原始碼]
首先,確定你已安裝必須的工具包。安裝 base-devel包 元軟件包應當足夠;它會引入 make(1) 和其它一些編譯源碼時需要的工具。
創建包的一個關鍵工具是 makepkg(由 pacman包 提供),它的功能請參閱 Arch 打包準則#Makepkg 的任務。
下載並測試安裝[編輯 | 編輯原始碼]
下載你想打包的軟件的原始碼壓縮包,解壓,按照作者所説的步驟安裝它。記錄下在編譯和安裝軟件過程中需要的所有命令或步驟。你將要在 PKGBUILD
文件中重複這些命令和步驟。
大多數軟件作者遵循三步走的安裝慣例:
$ ./configure $ make # make install
如果你要測試程序能否正常工作,建議在這部分測試。
創建一個乾淨的 chroot[編輯 | 編輯原始碼]
建議參考創建一個乾淨的 chroot 來保證你的系統中的其它軟件包和配置不會影響 PKGBUILD
。這個方法容錯性更強,是一個更加恰當的構建軟件包的方法,通常能夠發現那些你未曾意識到需要的依賴項,因為它們已經在你的系統中存在。
創建PKGBUILD[編輯 | 編輯原始碼]
當你運行makepkg
時,它會在當前工作目錄尋找一個PKGBUILD
文件。如果找到PKGBUILD
文件,它會下載該軟件的原始碼,根據PKGBUILD
文件中的指令編譯它。PKGBUILD中的指令必須能完全被Bash解釋。成功完成後,最後的二進制文件和包的元信息(即包的版本、依賴)被一起打包在pkgname.pkg.tar.zst
文件包中,這個文件包可以使用pacman -U <package file>
來安裝。
要開始製作一個包,你應該先創建一個空工作目錄,進入該目錄,創建一個PKGBUILD
文件。你可以複製PKGBUILD模板(位於/usr/share/pacman/)到工作目錄,或者複製一個類似包的PKGBUILD也可以。如果你只想在別人的基礎上更改一些選項的話,後一種方法比較方便。
定義PKGBUILD變量[編輯 | 編輯原始碼]
PKGBUILD文件的編寫例子可以在/usr/share/pacman/
處找到。PKGBUILD文件中可能用到的一些變量意義的解釋可以在PKGBUILD中找到。
makepkg 定義了兩個變量,你應該在編譯和安裝的過程中使用它們:
srcdir
- makepkg將會把源文件解壓到此文件夾或在此文件夾中生成指向 PKGBUILD 裡 source 數組中文件的軟連接。
pkgdir
- makepkg會把該文件夾當成系統根目錄,並將軟件安裝在此文件夾下。
這些變量都是絕對路徑, 即意味着, 如果你合適地使用這些變量, 就不用擔心當前工作目錄的影響.
PKGBUILD 函數[編輯 | 編輯原始碼]
一共有五個函數, 以下按照它們執行的先後順序列出。package()
函數是每個 PKGBUILD 中必須的函數,其餘不存在的函數可以跳過。
prepare()[編輯 | 編輯原始碼]
此函數會執行用於預處理源文件以進行構建的命令, 例如 patching. 此函數執行在 build() 之前, 軟件包解壓之後. 如果解壓過程被跳過 (makepkg -e
), 那麼 prepare()
函數就不會被執行.
bash -e
模式下, 意味着任何以非零狀態退出的命令都會造成該函數中止.不清楚應該放到 prepare()
還是 build()
, 只需要記得 prepare()
中的步驟僅在解壓後執行一次,而 build()
中的步驟會在每次編輯後都執行一次。
pkgver()[編輯 | 編輯原始碼]
pkgver()
會在抓取並解壓源文件,執行 prepare() 後執行此函數。
為使用 git/svn/hg 等工具的項目打包時,由於它們的構建過程相同, 但源文件可能每天甚至每小時更新一次,這一特性將會十分有用。過去的方法是把日期寫入到 pkgver 變量中, 但這樣一來 makepkg 會在即使軟件沒有更新的情況下依然重新構建軟件包, 因為它會認為軟件包的版本改變了. 其他與此有關的命令有 git describe
, hg identify -ni
等等. 請在提交 PKGBUILD 前做好測試, 因為如果 pkgver()
執行失敗, 整個構建過程都會終止.
-
). 通常都會用 sed 來進行修改.build()[編輯 | 編輯原始碼]
現在你需要編寫PKGBUILD
文件中的build()
函數。這個函數使用通用的shell命令來自動編譯軟件並創建軟件的安裝目錄。這允許makepkg無需詳查你的文件系統就可以打包你的軟件。
在build()
函數中第一步就是進入由解壓源碼包所生成的目錄。 makepkg 會在執行 build()
函數之前更改當前目錄為 $srcdir
; 因此, 大多數情況下第一條命令是這樣的(參考示例文件/usr/share/pacman/PKGBUILD.proto
):
cd "$srcdir/$pkgname-$pkgver"
現在,你需要把你當時手動編譯軟件時用到的命令一一列上。build()
基本上會自動運行你當時手動輸入的命令並在偽root環境下編譯該軟件。如果你要打包的軟件使用了一個配置腳本,最好在配置中加上--prefix=/usr
。許多軟件都將自己安裝到/usr/local
下,我們僅僅推薦當你手動從源碼安裝時這麼做。所有的Arch Linux軟件包都應當使用/usr
目錄。
./configure --prefix=/usr make
build()
函數. 但package()
函數依然是必須的.check()[編輯 | 編輯原始碼]
用來執行make check
和其他一些例行測試的地方。如果不需要可以通過在 PKGBUILD/makepkg.conf 中使用 BUILDENV+=('!check')
或者給 makepkg
傳入參數 --nocheck
來禁用它。
package()[編輯 | 編輯原始碼]
最後一步就是把編譯好的文件放到pkg
文件夾——一個簡單的偽root環境。pkg
目錄複製了根目錄下軟件安裝路徑的繼承關係。如果你需要手動把文件放到根目錄下,那麼在這裏你需要把文件放在pkg
下相同的文件層級結構中。比如,你想把一個文件安裝到/usr/bin
,那麼在偽root環境中對應的路徑為$pkgdir/usr/bin
。極少情況下的安裝步驟需要用户手動複製大量的文件到某個地方。大部分軟件安裝時只需要調用make install
即可。為了將軟件安裝到正確的路徑,最後一行一般應該這樣寫:
make DESTDIR="$pkgdir/" install
Makefile
裡沒有使用DESTDIR
;你可能需要使用prefix
來替代。如果軟件包是用autoconf/automake來創建的,那就使用DESTDIR
;如果DESTDIR
不起作用,試試make prefix="$pkgdir/usr/" install
。如果這還不起作用的話,你就需要深入檢查軟件的安裝命令了。makepkg --repackage
命令只運行package()
函數,它只是將文件打包成軟件包,並不運行編譯過程。如果你只是更改了PKGBUILD中的依賴,用這個命令來打包可以節省很多時間。
測試PKGBUILD文件[編輯 | 編輯原始碼]
你在寫PKGBUILD
的 build()
方法時,會想頻繁的測試你所做的改動以確保沒有bug。你可以在包含 PKGBUILD
的目錄下運行makepkg
命令來確保沒有問題。如果PKGBUILD
沒有錯誤,將會生成一個包,但是如果PKGBUILD
被破壞或未完成,它將拋出一個錯誤。
如果運行makepkg
成功,在你工作的目錄下將會生成一個名為$pkgname-$pkgver.pkg.tar.gz的新文件。這個文件可以使用pacman -U
或 pacman -A
安裝,你也可以將它加到本地或網上的軟件倉庫中。注意,一個包被構建並不代表你的工作就完成了!只有當所有文件的結構都正確才能確保完成,例如你給了一個不正確的前綴就不行。你可以使用pacman的查詢功能顯示軟件包包含的文件及依賴的文件,然後將它於你認為正確的對比。"pacman -Qlp <package file>" 和"pacman -Qip <package file>" 可以完成這項工作。
如果包看起來是正確的,那你的工作就完成了。但是如果你打算發佈這個包或PKGBUILD,你就需要確認確認再確認包的依賴關係。
同樣要確保安裝的軟件確實很完美的運行!如果你釋放了一個包括所有必需文件的包,但是由於一些配置選項使它不能很好的工作,這真是讓人惱火。如果你只是為你自己的系統安裝這個軟件,你就不必做這個質量保證了,因為只有你一個人需要忍受這些錯誤。
檢查包的邏輯性[編輯 | 編輯原始碼]
確定包可以正常使用後,再使用namcap來檢查錯誤:
$ namcap PKGBUILD $ namcap <package file name>.pkg.tar.zst
Namcap將會做以下工作:
- 檢查PKGBUILD文件裡的一些常見錯誤
- 用
ldd
掃描包中所有的ELF文件,自動報吿缺失或可去除的依賴。 - 啟發式搜尋缺失或冗餘的依賴。
要養成用namcap檢查包的習慣,以避免提交包後再做修復的麻煩。
把包提交給AUR[編輯 | 編輯原始碼]
請參考AUR submission guidelines,裏面詳細介紹了提交流程。
總結[編輯 | 編輯原始碼]
- 下載你希望打包的軟件原始碼
- 試着編譯安裝包到任意目錄
- 複製PKGBUILD的文件模板
/usr/share/pacman/PKGBUILD.proto
到一個臨時的目錄並重命名為PKGBUILD
- 根據具體情況修改 PKGBUILD 文件
- 運行
makepkg
看看輸出的打包結果是否正確 - 如果不正確,重複前兩個步驟
注意事項[編輯 | 編輯原始碼]
- 在開始自動打包之前,請確保你至少已成功手動打包一次,除非你「很清楚」你正在做什麼。不幸的是,雖然大多數軟件作者遵循了三步走的安裝慣例:
./configure
;make
;make install
,但事情並不都是這樣的,有時候你不得不自己打補丁才能安裝成功。經驗是:如果你手動無法編譯成功或者無法將軟件安裝到指定子目錄下,那你就不必費心打包了。makepkg
沒有任何魔力能消除原始碼的問題讓你編譯成功。 - 在一些情況下,你可能無法直接得到包的源碼,可能需要使用
sh installer.run
這樣的東西來工作。這時就需要你自己做很多工作了(比如讀READMEs,安裝指導,手冊,或者Gentoo的ebuilds等等)。在一些很變態的情況下,你需要自己編輯源碼才能正常安裝。但是,makepkg
需要完全自主運行,不能有用户的干預。因此,如果你想修改makefiles,你需要隨PKGBUILD附上一個定製的補丁,然後在prepare()
函數裏安裝這個補丁;或者你可以在prepare()
函數裏通過sed
來修改。
更詳細的規則[編輯 | 編輯原始碼]
32 位 – CLR – CMake – Cross – DKMS – Eclipse – Electron – Font – Free Pascal – GNOME – Go – Haskell – Java – KDE – 內核模塊 – Lisp – Meson – MinGW – Node.js – Nonfree – OCaml – Perl – PHP – Python – R – Ruby – Rust – VCS – Web – Wine
PKGBUILD 生成器[編輯 | 編輯原始碼]
某些軟件包的 PKGBUILD 可以通過工具自動生成。
- Haskell: cblrepo, arch-hs包
- Node.js: nodejs-npm2archAUR
- Perl: perl-cpanplus-dist-arch包
- Python: pipman-gitAUR, pip2arch-gitAUR, python-pypi2pkgbuildAUR
- Ruby: gem2archAUR, pacgemAUR
- Rust: cargo-pkgbuildAUR