跳至內容
出自 Arch Linux 中文维基

本頁面討論 PKGBUILD 中可由維護者定義的變量。若要獲取關於 PKGBUILD 中的函數和創建軟體包的基本信息,請參考創建軟體包PKGBUILD(5)

PKGBUILD 是一個 Bash 腳本,包含在構建 Arch Linux 軟體包時需要的信息。

Arch Linux 使用 makepkg 構建軟體包。當 makepkg 運行時,它會在當前目錄尋找 PKGBUILD 文件,並依照其中的指令編譯或獲取所需的文件,並生成 pkgname.pkg.tar.zst 軟體包。生成的包內有二進制文件和安裝指令,可以使用 pacman 進行安裝。

必須定義的變量有 pkgnamepkgverpkgrelarch。在構建軟體包時不強制要求定義 license,但若要分享 PKGBUILD 文件給其他人,推薦加上該變量,否則 makepkg 會提示相關報錯。

一般來說,建議但不強制要求按照下面的順序在 PKGBUILD 文件中定義這些變量。

提示:
  • 使用 namcap 來檢查 PKGBUILD 文件中的常見打包問題。
  • 可以使用 shellcheck(1) 來檢查 PKGBUILD 中的常見語法錯誤,並排除 SC2034SC2154
shellcheck --shell=bash --exclude=SC2034,SC2154 PKGBUILD

軟體包名稱

pkgbase

在構建常規的軟體包時,不應該在 PKGBUILD 文件中顯式定義該變量,這個值默認會與 #pkgname 的值相同。

構建拆分包時,這個變量可用於在 makepkg 的輸出和純原始碼包中指定軟體包組。此變量不允許以下劃線開頭。若該變量沒有明確定義,則會默認對應到 pkgname 數組的第一個元素。

拆分軟體包中的所有選項和指令都默認使用 PKGBUILD 中全局定義的值。以下選項可以在拆分包的打包函數中覆寫:#pkgdesc#arch#url#license#groups#depends#optdepends#provides#conflicts#replaces#backup#options#install#changelog

pkgname

對於常規的軟體包,這個變量設定軟體包的名稱,例如 pkgname='foo'。對於拆分包則是一個名稱的序列,例如 pkgname=('foo' 'bar')。名稱只能由由小寫字母、數字和 @ . _ + - (at 符號、英文句點、下劃線、加號、連字符)構成,且不能以連字符或英文句點開頭。為了保證一致性,pkgname 應該與軟體的原始碼文件相匹配。比如:源文件包名為 foobar-2.5.tar.gz,那麼應該使用 pkgname=foobar

版本

pkgver

軟體包的版本號,應該與軟體上游發布的版本號一致。變量的值可以由字母、數字和英文句點 .,下劃線 _ 組成,但不能包含連字符(-)。如果上游版本號中使用了連字符,則應該用下劃線 _ 來替代。在之後的 PKGBUILD 指令中pkgver 中的下劃線可以用下面這個方法替換回連字符:source=("${pkgname}-${pkgver//_/-}.tar.gz")

注意:如果上游使用時間戳格式的版本號,例如 30102014,請修改為年份在前的格式 20141030ISO 8601 格式)。否則新版本可能無法被系統識別出來是新的。
提示:

pkgrel

軟體的發布號。這通常是一個正整數,用來區分同一版本軟體的多次構建。當軟體包的補丁和附加功能被添加進入 PKGBUILD,從而導致生成的軟體包發生變化時,pkgrel 應該增加 1。而當這個軟體包發布一個新版本時,發布號重置為 1。在個別情況下,也會有其他的發布號形式。比如主版本號.次要版本號

epoch

警告:除了特別、絕對、顯式要求需要這樣做,否則不允許使用 epoch 變量。

用於強制升級軟體包。在判定邏輯中,不論版本號如何,只要 epoch 值較大,就會被視為更新的軟體包。這個值應為非負整數,且默認值為 0。通常當一個軟體的版本編號方式改變(或者使用某些字母-數字混編的版本符號),導致正常的版本比較邏輯無法進行時,會使用這個變量來控制升級。比如:

pkgver=5.13
pkgrel=2
epoch=1
1:5.13-2

更多關於版本比較的信息,參見 pacman(8)

一般變量

pkgdesc

軟體包描述。建議最多 80 個字符,並不要自引軟體包的名字,除非軟體包名和程序名不相同。比如:pkgdesc='Nedit is a text editor for X11' 應該被寫成 pkgdesc='Text editor for X11'

合理地在描述中使用關鍵字,這樣可以使軟體包在相關的搜索中出現的可能性增加。

arch

一個描述能夠生成並運行該軟體包的架構的數組。Arch 官方僅支持 x86_64, 但是其它項目提供了其它架構支持。比如說,Arch Linux 32 提供了 i686pentium4 支持;Arch Linux ARM 項目提供 armv7h (帶有硬體浮點運算模塊的 armv7)和 aarch64 (64 位 armv8) 的支持。

這個數組有兩種形式:

  • arch=('any') 表明軟體包可以在任意架構上生成,並且一旦編譯完成,編譯時的架構就不再有影響了(例如 shell 腳本、字體、主題、各種擴展、Java 程序等)。
  • arch=(...) 包含一個或更多架構(any除外),表明這個軟體包可以在上述的任意架構上生成,但生成產物只能在編譯它的架構上運行。對於這些軟體包,您必須在 PKGBUILD 文件中指定所有官方支持的架構。對於官方軟體源和 AUR 軟體包,這指的是 arch=('x86_64')。不過,AUR 軟體包可以選擇添加一些已知的兼容架構的支持。

在生成過程中可以通過 $CARCH 變量來獲知目標架構。

url

待打包軟體官方站點的網址。

license

本文或本章節可能需要合併到Arch 打包準則#授權協議

附註: PKGBUILD 格式並沒有強制執行某種打包標準。(在 Talk:PKGBUILD 中討論)

這篇文章的某些內容需要擴充。

原因:更多信息請參考 [1]。 (在 Talk:PKGBUILD 中討論)

軟體分發所使用的許可證。Arch Linux 使用 SPDX 許可證標識符,所有許可證都需在 /usr/share/licenses/ 下有對應項。

licenses 包含了常見許可證(例如 GPL-3.0-or-later)的對應文件,默認已作為 base 元軟體包的依賴之一安裝在 /usr/share/licenses/spdx/ 目錄下,使用時只需引用 SPDX 標識符清單中的標識符。

類似 BSD 或 MIT 的許可證族嚴格來說不是特定的單個許可證,每個實例都需要獨立的許可證文件。對於這些許可證,需要在 license 中使用通用 SPDX 標識符(例如 BSD-3-ClauseMIT),並像自定義許可證一樣提供對應的許可證文件。

對於自定義許可證,如果其不屬於常見許可證族,就需要使用 LicenseRef-license-namecustom:license-name 作為標識符。對應的許可證文件必須放置在 /usr/share/licenses/pkgname 目錄下。可以在 package() 中使用如下代碼安裝許可證文件:

install -Dm644 LICENSE "${pkgdir}/usr/share/licenses/${pkgname}/LICENSE"
注意:pkgdir 變量由 makepkg 定義,具體信息請參考 PKGBUILD(5) § PACKAGING FUNCTIONS

如果要結合多個許可證或添加例外,需要遵循 SPDX 語法。例如,如果軟體包發布於 GNU/GPL 2.0 GNU/LGPL 2.1,需要使用 'GPL-2.0-or-later OR LGPL-2.1-or-later';如果軟體包發布於 Apache 2.0 並帶有 LLVM 例外,需要使用 'Apache-2.0 WITH LLVM-exception';如果軟體包部分發布於 BSD 3 clause,其它部分發布於 GNU/LGPL 2,還有一部分發布於 GNU/GPL 2.0,就需要使用 'BSD-3-Clause AND LGPL-2.1-or-later AND GPL-2.0-or-later'[2]。注意,這需要是單個字符串,因此需要將整個表達式用引號括起來。截至 2023 年 11 月為止,SPDX 例外列表還非常有限,因此你通常還是需要遵循添加自定義許可證的方式。

如果在 SPDX 標識符方面遇到問題,可以在過渡期間使用舊標識符(/usr/share/licenses/common 中的目錄名稱)。

另請參考 Nonfree applications package guidelines

有關自由和開放源碼軟體許可證的更多信息和觀點,請參閱以下網頁:

groups

軟體包所在的軟體包組。例如:當你安裝 plasma包組,它會安裝組裡的所有包。

依賴關係

注意:架構相關的額外依賴可以通過在名稱後添加下劃線和架構的方式指定,例如 optdepends_x86_64=()

depends

為了生成運行軟體,而必須安裝的包列表。如果是只在運行時才依賴的包,請在 package() 函數中定義。

可以使用比較運算符來描述版本限制。例如 depends=('foobar>=1.8.0')。如有多重限制,你可以添加多條,例如 depends=('foobar>=1.8.0' 'foobar<2.0.0')

本文或本章節可能需要合併到Arch 打包準則

附註: PKGBUILD 格式並沒有強制執行某種打包標準。(在 Talk:PKGBUILD 中討論)

depends 應該列出所有的直接依賴,即使已由某個依賴項間接引入時也應該如此。如果不這樣做,那可能會發生以下情況:如果一個軟體包 foo 依賴 barbaz 兩個軟體包,而 bar 軟體包也依賴於 baz 軟體包,當 bar 軟體包不再依賴於 baz 就極有可能會導致意外行為 —— pacman 不會在安裝 foo 軟體包時安裝 baz 軟體包,也會在清除孤兒軟體包時把 baz 清理掉。由於 baz 軟體包被依賴卻沒有被安裝,foo 可能崩潰或者發生運行錯誤。

但在一些情況下,上面所述的某些依賴是沒有必要或者不應該被列出的。比如說 glibc,每個作業系統都需要 C 運行庫,因此它是不能夠被卸載的。又比如,當軟體包已經依賴於一個以 python- 開頭的模塊,就不需要再單獨依賴 python —— 因為 python- 開頭的模塊必定依賴於 python 軟體包,而且不允許從依賴列表中刪除。

通常的依賴應該包括生成所有可選功能所需的依賴。否則,對於任何依賴於額外軟體包的可選功能,應顯式通過配置選項將其禁用。如果不這樣做,會給軟體包添加了所謂「自動魔法依賴」:一些生成時可選功能因為生成軟體包的機器上安裝的一些傳遞依賴或者不相關的軟體被意外啟用了,但是沒有表現在包的依賴中。

如果依賴的名稱寫成了庫的名稱(例如 depends=('libfoobar.so')),makepkg 會在編譯完成的包中嘗試尋找依賴這個庫的二進制文件,並添加二進制文件所需的 soname 版本號到依賴列表中。可以自己加上版本號來停用自動檢測,比如說 depends=('libfoobar.so=2')

makedepends

僅在軟體生成時需要的軟體包列表。可以像 depends 序列一樣指定依賴的版本限制。depends 序列裡面的軟體包默認也是生成時需要的,此處不應該重複。

注意:
  • 在使用 makepkg 構建軟體包時,默認 base-devel 已安裝。該包的依賴項不應該出現在 makedepends 列表中。
  • 如果使用 VCS 源,記得要把對應的 VCS 工具(gitsubversioncvs 等等)加進去。
提示:用以下命令查看某個依賴項是否已經被 base-devel 直接依賴:pactree -rsud1 package | grep base-devel(需要安裝 pacman-contrib)。

checkdepends

運行軟體的測試組件時需要,而運行時不需要的包列表。該列表中的包遵循 depends 相同的格式。這些依賴只在 check() 函數存在,且被 makepkg 執行時會被處理。

注意:在使用 makepkg 構建軟體包時,默認 base-devel 已安裝。該包的依賴項不應該出現在 checkdepends 列表中。

optdepends

可選軟體包序列。這些可選軟體包不影響軟體主要功能,但能提供額外特性。這通常意味著除非安裝了對應的可選軟體包,該軟體包所提供的個別可執行文件可能無法正常使用[3]。如果軟體有一些替代依賴,您可以將其在此處全部列出,而不是 depends 列表中列出。

應該簡要說明每個包所能提供的額外功能,例如:

optdepends=('cups: printing support'
            'sane: scanners support'
            'libgphoto2: digital cameras support'
            'alsa-lib: sound support'
            'giflib: GIF images support'
            'libjpeg: JPEG images support'
            'libpng: PNG images support')

包關係

注意:架構相關的附加列表可以通過在變量名稱後添加下劃線和架構名字的方式指定,例如 conflicts_x86_64=()

provides

該列表說明的是本軟體包能夠提供列表中的包(或者像 cronsh 這樣的虛包所有外部共享庫)所提供的功能。只要 provides 列表中的包都沒有聲明 conflicts,提供相同功能的軟體包就可以同時安裝。

注意:
  • 該變量中的軟體包應當加上版本號(pkgver,可能的話還有pkgrel),特別是當依賴該軟體包的其他軟體對版本號特別敏感的時候。就是說,如果一個修改過的 qt 包其版本號為 3.3.8,命名為 qt-foobar,那麼 provides 應該寫成 provides=('qt=3.3.8')。如果忽略了版本號,會導致所有依賴於 qt 的某個特定版本的包編譯失敗。
  • 不要把 pkgname 加入 provides 序列。這個操作會自動進行。

conflicts

這個列表描述的是與當前軟體包衝突的包,或者與該包同時存在會產生問題的包。安裝此軟體時,這個列表中的所有軟體包和提供這個功能的軟體包都會被刪除。可以像 depends 那樣指定衝突包的版本號。

需要注意的是,衝突檢查的對象是 pkgname 以及 provides 中的名字。因此,如果你的包 provides foo 功能,在 conflicts 中指定 foo 就會導致你的包和所有其他在 provides 中包含了 foo 的包衝突(也就是說,你不需要一個一個地指定所有衝突的包的名字)。例子是:

  • netbeans 提供 netbeans(因為 pkgname 就是如此)。
  • netbeans-cppAUR 提供 netbeans 功能,並和 netbeans 衝突。
  • netbeans-phpAUR 提供 netbeans 功能,而且和 netbeans 衝突,但是不需要再說明它與 netbeans-cppAUR 衝突,因為提供相同功能的包隱含了衝突關係。

當不同的包通過在 provides 列表中聲明的方式提供相同的功能,那麼是否特意在 conflicts 列表中添加可替換的包會產生不同的結果。特意說明的話,兩個包就會被認為是可相互替代的;如果 conflicts 列表不存在,那麼兩個包會被認為是「可能可以同時存在」。在決定是否需要聲明 conflicts 列表的時候,請忽略 provides 列表的內容,獨立決策。

replaces

會因安裝當前包而取代的過時的包的列表。比如:wireshark-qt 中的 replaces=('wireshark')。在同步軟體資料庫後,pacman 會立刻用軟體庫中的另一個包替換掉 replaces 中已安裝的包。如果你只是提供已存在包的一個替代品,或者上傳到 AUR, 請不要使用 replace,而是使用 conflictsprovides 兩個變量 —— 它們僅在安裝衝突軟體包時被檢查。

其它

backup

當包被升級或卸載時,應當保留的文件(的路徑)序列。這些文件一般是用戶會更改的文件,如主要放置在 /etc 中的配置文件。如果在安裝軟體包後這些文件沒有被修改過,那麼它們會隨升級和移除軟體包時一同被替換或刪除。

列表中的文件應該使用相對路徑,即不是以斜槓(/)開頭的路徑(如 etc/pacman.conf 而不是 /etc/pacman.conf)。backup 數組不支持空目錄和類似「*」的通配符

在升級時,新版本會被命名為 file.pacnew 以避免覆蓋原來的被用戶修改過的文件。當卸載包時,用戶修改過的文件會以 file.pacsave 為名而保留下來 —— 除非用 pacman -Rn 命令卸載。

參見 pacnew 和 pacsave 文件獲取更多信息。

options

參見 PKGBUILD(5) § OPTIONS AND DIRECTIVES 以獲取所有可用選項。

install

需要包含在包中的 .install 腳本的名稱。

pacman 可以在安裝、卸載或升級一個軟體包時存儲及執行一些特定的腳本。腳本包含了下面幾個函數,並且在特定時刻執行它們:

  • pre_install - 提取包中文件前運行的腳本。會傳遞一個參數:新版本號。
  • post_install - 提取包中文件後運行的腳本。安裝軟體包後輸出的提示信息需放置於該函數內。會傳遞一個參數:新版本號。
  • pre_upgrade - 提取包中文件前運行的腳本。兩個參數會按以下順序傳遞:新版本號,舊版本號。
  • post_upgrade - 提取包中文件後運行的腳本。兩個參數會按以下順序傳遞:新版本號,舊版本號。
  • pre_remove - 文件被刪除前運行的腳本,會傳遞一個參數:舊版本號。
  • post_remove - 文件被刪除後運行的腳本,會傳遞一個參數:舊版本號。

每一個函數都是 chrootpacman 安裝目錄下運行的。參見這個帖子.

提示:
注意:腳本不要以 exit 結束,否則包含該腳本的函數無法執行。

changelog

軟體包的更新日誌的文件名。要查看安裝軟體的更新日誌(如果有):

$ pacman -Qc pkgname

源碼

source

構建軟體包時需要的文件列表。它必須包含軟體源的位置,大多數情況下是一個完整的 HTTP 或 FTP 地址。您可以在此處調用前面提到的變量 pkgnamepkgver,來實現高效的命名(如 source=("https://example.com/${pkgname}-${pkgver}.tar.gz"))。

文件也可以放到與 PKGBUILD 文件相同目錄,並將文件名添加到這個列表。在實際的編譯過程開始之前,所有該列表中引用的文件都會被下載或檢查是否存在,如果有文件丟失 makepkg 就不會繼續。

.install 文件會被 makepkg 自動識別,而不應該被包含在這個列表中。makepkg 會自動把 source.sig.sign.asc 結尾的文件當成 PGP 簽名,並自動驗證對應的源文件的完整性。

警告:因為所有包的 SRCDEST 的值可能相同,所以下載的文件的文件名需要唯一。比如說,如果一個項目只用版本號來命名,可能會與其他有相同版本號的不同項目衝突。在這種情況下,你可以為下載的文件指定不同的文件名:source=('unique_package_name::file_uri')。例如 source=("${pkgname}-${pkgver}.tar.gz::https://github.com/coder/program/archive/v${pkgver}.tar.gz")
注意:
  • 架構相關的文件可以通過在名稱後添加下劃線和架構的方式指定,例如 source_x86_64=()。必須提供對應的完整性校驗和序列,例如 sha256sums_x86_64=()
  • 有些伺服器通過 User-Agent 或其它方式來篩選並限制下載。這個限制可以通過 DLAGENTS 規避。
  • 可以使用 file:// URL 來指向本地目錄或文件,例如指定本地 Git 倉庫:"${pkgname}::git+file:///path/to/repository"
  • Magnet link support can be added using transmission-dlagentAUR as DLAGENT and using the magnet:// URI prefix instead of the canonical magnet:?.
  • See PKGBUILD(5) § USING VCS SOURCES and VCS 軟體打包準則#VCS 原始碼 for details on VCS specific options, such as targeting a specific Git branch or commit.

noextract

一個在 source 中列出,但不應該由 makepkg 解包的文件列表。這通常包括那些不能被 /usr/bin/bsdtar 處理的壓縮文件,或者本來就不需要解壓、按照原樣提供的文件。對於前者,需要將額外的解包工具(如 unzipp7ziplrzip 等)加入 makedepends 序列,且 prepare() 函數的第一行需進行手動解壓。例如:

prepare() {
  lrzip -d source.tar.lrz
}

注意當 source 是一些 URL 時,noextract 僅僅取文件名部分:

source=("http://foo.org/bar/foobar.tar.xz")
noextract=('foobar.tar.xz')

不提取任何東西時,可以像這樣:

  • 如果 source 只包含了純 URL,而沒有自定義的文件名時,將內容從最後一個斜槓之前像這樣從 source 序列中提出來:
noextract=("${source[@]##*/}")
noextract=("${source[@]%%::*}")

validpgpkeys

PGP 指紋列表。如果使用,makepkg 僅接受這裡定義的簽名,並且忽略密鑰環中的值。如果原始碼用子密鑰簽名,makepkg 仍然會使用主密鑰進行比較。

此處僅接受完整的指紋。它們必須是大寫字母而且不能有空白字符。

注意:可以使用 gpg --list-keys --fingerprint KEYID 查找密鑰的指紋。

請參閱 makepkg#驗證簽名了解簽名驗證過程的詳細信息。

完整性檢驗

下面描述的這些序列中的變量是 source 序列中對應文件的校驗和。可以插入 SKIP 跳過某個不需要檢驗的文件。

校驗和的類型和數值應該始終使用上游提供的數值(比如在新版本公告中的)。當存在多種類型的時候,最好選用最強的校驗類型。類型按照從強到弱的順序如下:b2 > sha512 > sha384 > sha256 > sha224 > sha1 > md5 > ck,這樣可以最大限度地保證從上游的公告到軟體包的生成整個流程中下載文件的完整性。

注意:另外,當上游具備數字簽名文件時,這個簽名文件應該被添加到 source 序列中,PGP 密鑰添加到 validpgpkeys 序列中。這樣允許在生成軟體包時進行驗證。

makepkg-g/--geninteg 選項可以自動生成校驗值,通常可以通過 makepkg -g >> PKGBUILD 命令寫入。pacman-contrib 提供的 updpkgsums(8) 命令也可以更新 PKGBUILD 中的變量。兩個工具都會自動檢測 PKGBUILD 中的算法, 如果沒找到就回滾到 md5sums

The file integrity checks to use can be set up with the INTEGRITY_CHECK option in /etc/makepkg.conf. See makepkg.conf(5).

注意:架構相關的額外完整性檢驗可以通過在名稱後添加下劃線和架構的方式指定,例如 sha256sums_x86_64=()

b2sums

BLAKE2 校驗和數組,大小為 512 位。

sha512sums,sha384sums,sha256sums,sha224sums

SHA-2 校驗和數組,大小分別為 512,384,256 和 224 位。最常見的是 sha256sums

sha1sums

source 數組中文件的 160 位 SHA-1 校驗和數組。

md5sums

source 數組中文件的 128 位 MD5 校驗和數組。

cksums

source 數組中文件的 CRC32(使用 UNIX 標準的 cksum)校驗和數組。