創建軟體包 - Arch Linux 中文维基

跳至內容

# 創建軟體包

出自 Arch Linux 中文维基
翻譯狀態：

- 本文（或部分內容）譯自 Creating packages，最近一次同步於 2026-01-19，若英文版本有所更改，則您可以幫助同步與翻譯更改的內容。
- 您可以在 ArchWiki 的對應頁面找到本文翻譯的原始修訂歷史。
- 本文可能與英文原文存在出入。

相關文章

- Creating packages for other distributions
- 軟體包補丁
- .SRCINFO

本文旨在幫助用戶利用類似於 ports 的 Arch 構建系統來創建自己的軟體包，以及如何提交到 Arch 用戶軟體倉庫。本文講述了如何創建 PKGBUILD(5)，這是一個描述如何構建軟體包的文件，makepkg 會使用它來從原始碼創建二進制軟體包。

關於構建規則和提高軟體包質量的方法，請參考 Arch 打包準則。

## 概述

Arch Linux 中的軟體包是通過 makepkg 工具以及存儲在 `PKGBUILD` 文件中的信息編譯的。運行 makepkg 時，它會自動在當前目錄下搜索 `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` 軟體包文件中，這個文件包可以通過 `makepkg --install` 調用 pacman 或直接使用 `pacman -U <package file>` 來安裝。

要開始製作一個包，你應該先創建一個空工作目錄，進入該目錄，創建一個 `PKGBUILD` 文件。你可以複製 `PKGBUILD` 模板（位於 /usr/share/pacman/）到工作目錄，或者複製一個類似包的 `PKGBUILD` 也可以。如果你只想在別人的基礎上更改一些選項的話，後一種方法比較方便。

### PKGBUILD 變量

注意：主頁面為 PKGBUILD，另外也請參考 PKGBUILD(5) § OPTIONS AND DIRECTIVES。

makepkg 預定義了以下變量，打包者需使用它們指代構建過程的臨時路徑：

`srcdir`
  makepkg將會把源文件解壓到此文件夾，或在此文件夾中生成指向 source 數組中文件的軟連接。
`pkgdir`
  makepkg會把該文件夾當成系統根目錄，並將軟體安裝在此文件夾下。

這些變量都是絕對路徑，即意味著只要你合適地使用這些變量，就不用擔心當前工作目錄的影響.

注意：makepkg 及延伸到 `build()` 和 `package()` 函數在運行過程中都應當是非交互的。在這些函數中調用交互工具或腳本可能會中斷 makepkg 的運行，特別是啟用了構建日誌的時候（`--log`）。具體信息請參考 FS#13214。

### PKGBUILD 函數

在構建軟體包時，`makepkg` 會在 `PKGBUILD` 中有定義的情況下調用以下五個函數。`PKGBUILD` 中必須包含 `package()` 函數並總會被調用。對於其它函數，如果其未被定義，那麼 `makepkg` 會將其略過。

在構建時，函數將按下文列出的順序執行。

另請參考 PKGBUILD(5) § PACKAGING FUNCTIONS。

#### prepare()

此函數會執行用於預處理源文件以進行構建的命令，例如 patching。此函數執行在 pkgver() 之前，軟體包解壓之後。如果解壓過程被跳過（`makepkg --noextract`），那麼 `prepare()` 函數就不會被執行。

注意： (從 PKGBUILD(5)) 中可以知道，該函數運行在 `bash -e` 模式下，意味著任何以非零狀態退出的命令都會造成該函數中止.

如果不清楚應該將操作放到 `prepare()` 還是 `build()`，只需要記得 `prepare()` 中的步驟應在解壓後僅執行一次，而 `build()` 中的步驟應在解壓後文件被修改時都執行一次。

#### pkgver()

`pkgver()` 會在抓取並解壓源文件，執行 prepare() 後執行此函數，可用於在 makepkg 階段中更新 pkgver 變量。

為使用 git/svn/hg 等工具的項目打包時，由於它們的構建過程相同，但源文件可能每天甚至每小時更新一次，這一特性將會十分有用。過去的方法是把日期寫入到 pkgver 變量中，但這樣一來 makepkg 會在即使軟體沒有更新的情況下依然重新構建軟體包，因為它會認為軟體包的版本改變了。其他與此有關的命令有 `git describe`，`hg identify -ni` 等等。請在提交 PKGBUILD 前做好測試，因為如果 `pkgver()` 執行失敗，整個構建過程都會終止。

注意：pkgver 不能含有空格或連接符 (`-`)，通常可以用 sed 來進行修正。

#### build()

現在你需要編寫 `PKGBUILD` 文件中的 `build()` 函數。這個函數使用 Bash 語法的通用 shell 命令來自動編譯軟體，並創建名為 `pkg` 的軟體安裝目錄。這允許 makepkg 無需詳查你的文件系統就可以打包你的軟體。

在 `build()` 函數中第一步就是進入由解壓源碼包所生成的目錄。makepkg 會在執行 `build()` 函數之前將當前活動目錄設為為 `$srcdir`；因此，大多數情況下第一條命令是這樣的：(參考示例文件 `/usr/share/pacman/PKGBUILD.proto`）：

    cd "$pkgname-$pkgver"

現在，你需要把你當時手動編譯軟體時用到的命令一一列上。`build()` 基本上會自動運行你當時手動輸入的命令，並在偽 root 環境下編譯該軟體。如果要打包的軟體使用了一個配置腳本，最好在配置中加上 `--prefix=/usr`。許多軟體都將自己安裝到 `/usr/local` 下，但你只應在手動從源碼安裝時這麼做。所有的 Arch Linux 軟體包都應當使用 `/usr` 目錄。文件中接下來的兩行應當如下（參考 `/usr/share/pacman/PKGBUILD.proto`）：

    ./configure --prefix=/usr
    make

注意：如果你的軟體不需要構建任何東西，請不要使用 `build()` 函數，但 `package()` 函數依然是必須的。

#### check()

用於執行 `make check` 和其它一些例行測試。強烈建議使用 `check()` 確保軟體正常構建，並能搭配依賴正常使用。

如果不需要或是維護者無法使軟體包通過測試，可以給 `makepkg` 傳入 `--nocheck` 參數來禁用它。

如果要測試的是 GUI 圖形化應用，可以在虛擬 xserver 中運行測試。

#### package()

最後一步是將編譯好的文件放到一個目錄下，讓 makepkg 可以獲取並打包為軟體包。默認情況下該目錄為 `pkg`——一個簡單的偽 root 環境。`pkg` 目錄複製了根目錄下軟體安裝路徑的繼承關係，如果你需要手動把文件放到根目錄下，那麼需要把文件放在 `pkg` 下相同的文件層級結構中。比如，你想把一個文件安裝到 `/usr/bin`，那麼在偽 root 環境中對應的路徑為 `$pkgdir/usr/bin`。安裝步驟通常不需要用戶手動複製大量文件到某個地方，而只需調用 `make install` 即可。為了將軟體正確地安裝到 `pkg` 路徑下，最後一行一般應該這樣寫：

    make DESTDIR="$pkgdir" install

注意：有時候在 `Makefile` 裡沒有使用`DESTDIR`；你可能需要使用 `prefix` 來替代。如果軟體包是用 autoconf/automake 來構建的，那就需根據文檔使用 `DESTDIR`；如果 `DESTDIR` 不起作用，可以試試 `make prefix="$pkgdir/usr" install`。如果這還不起作用的話，你就需要深入檢查 `make <...> install` 具體執行的安裝命令了。

`makepkg --repackage` 命令只運行 `package()` 函數,它只是將文件打包成軟體包，並不運行編譯過程。如果你只是更改了 `depends` 依賴變量，用這個命令來打包可以節省很多時間。

注意：使用類似 `mv` 的命令從 `$srcdir` 移動由 `build()` 生成的文件到 `$pkgdir` 會破壞 makepkg 的 `--repackage` 選項。

## 測試 PKGBUILD 文件和軟體包

在編寫 `build()` 函數時，需要頻繁測試更改以確保沒有 bug。你可以在包含 `PKGBUILD` 的目錄下運行 `makepkg` 命令來確保沒有問題。如果 `PKGBUILD` 沒有錯誤，將會生成一個軟體包；但是如果 `PKGBUILD` 有問題或未完成，它將拋出一個錯誤。

如果運行 `makepkg` 成功，在你的工作目錄下將會生成一個名為 `pkgname-pkgver.pkg.tar.zst` 的新文件，可以使用 `pacman -U` 進行安裝。注意，成功生成了軟體包不代表軟體能正常運行，它有可能僅包含有空目錄，也可能包含如不正確的前綴等問題。你可以使用 pacman 的 `pacman -Qlp pkgname` 查詢軟體包的文件清單，以及通過 `pacman -Qip pkgname` 檢查依賴項是否正確。

如果包看起來是正確的，那你的工作就完成了。但是如果你打算發布這個 `PKGBUILD` 文件，你就需要確認確認再確認 `depends` 數組中的依賴是否正確。

另外也要確保包二進制文件完全正常地運行！如果發布出去的軟體包已涵蓋所有必要文件，但僅因某些選項與其他系統不兼容而崩潰會非常令人討厭。如果你只是為自己的系統編譯這個軟體，就不必做這個質量保證了，因為只有你一個人需要忍受這些錯誤。

### 檢查包的邏輯性

確定包可以正常使用後，再使用namcap來檢查錯誤：

    $ namcap PKGBUILD
    $ namcap pkgname.pkg.tar.zst

Namcap 將會做以下工作：

- 檢查 `PKGBUILD` 裡的一些常見錯誤，以及包文件結構是否有不必要或錯位的文件
- 用 `ldd` 掃描包中所有的 ELF 文件，自動報告 `depends` 中缺失或可去除的依賴
- 啟發式搜尋缺失或冗餘的依賴

等等。

要養成用 namcap 檢查包的習慣，以避免提交包後再做修復的麻煩。

### 使用 pkgctl 在乾淨的 chroot 環境中進行構建

本文或本章節可能需要合併到Arch 構建系統#構建軟體包。

附註： 本文與構建系統無關，且與 #創建一個乾淨的 chroot 和 DeveloperWiki:Building in a clean chroot 重複。（在 Talk:創建軟體包 中討論）

可以使用 devtools包 的 `pkgctl` 來檢查軟體包是否可以在無其它包的環境中正常構建。在包含 PKGBUILD 的目錄下執行：

    $ pkgctl build

然後檢查輸出是否包含錯誤或警告。如果軟體包依賴於 AUR 包，則需要事先構建並帶入 chroot jail 中：

    $ pkgctl build -I path/to/somepkg.tar.gz -I ...

注意：如果包之前是通過 AUR 助手安裝的，那很可能緩存目錄中已經有其 tarball 了。

更多選項請參考 pkgctl-build(1)。

## 把包提交給 AUR

請參考 AUR 提交準則，裡面詳細介紹了提交流程。

## 總結

- 下載你希望打包的軟體原始碼
- 試著編譯安裝包到任意目錄
- 複製文件模板 `/usr/share/pacman/PKGBUILD.proto` 到一個臨時目錄，並重命名為 `PKGBUILD`
- 根據需要修改 `PKGBUILD` 文件
- 運行 `makepkg` 看看輸出的打包結果是否正確
- 如果不正確，重複前兩個步驟

### 注意事項

- 除非你「很清楚」你正在做什麼，否則在開始自動打包之前，需確保你至少已成功手動打包一次。不幸的是，雖然大多數軟體作者遵循了三步走的安裝慣例：`./configure`; `make`; `make install`，但事情並不都是這樣的，有時候你不得不自己打補丁才能安裝成功。經驗是：如果你手動無法編譯成功或者無法將軟體安裝到指定子目錄下，那你就不必費心打包了。`makepkg`沒有任何魔力能消除原始碼的問題讓你編譯成功。

- 在少數情況下，軟體包不提供源碼，而只能使用類似 `sh installer.run` 的命令進行安裝，這時就需要你自己做很多工作了（比如查看 README，安裝指導，手冊，或者 Gentoo 或其它軟體包安裝器的 ebuild 等等）。在一些很變態的情況下，你需要自己編輯源碼才能正常安裝。但是，`makepkg` 需要完全自主運行，不能有用戶的干預。因此，如果你想修改 makefiles，需要隨 `PKGBUILD` 附上一個定製的補丁，然後在 `prepare()` 函數裡安裝這個補丁；或者你可以在 `prepare()` 函數裡通過 `sed` 來修改。

## 自動化

### 校驗和

可以使用 `updpkgsums` 工具簡化為新版本軟體更新校驗和的工作，具體信息請參考 Makepkg#生成新校驗和。

### PKGBUILD 生成器

某些軟體包的 `PKGBUILD` 可以通過工具自動生成。

注意：用戶需要在提交文件到 AUR 前確保軟體包滿足高質量標準。

- 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，cargo-aur-binAUR

### 新的上游版本發布

來自 devtools包 的 pkgctl 以 `.nvchecker.toml` 配置文件的形式支持 nvchecker 集成，該文件需與 `PKGBUILD` 位於同一目錄下。具體示例請參考 pacman 包的 .nvchecker.toml 配置文件。

提示：`pkgctl version setup` 會通過分析 PKGBUILD 的 source 數組嘗試自動創建 `.nvchecker.toml` 配置文件。

完成配置後，可以使用 `pkgctl version check` 比較 `PKGBUILD` 中的 `pkgver` 來檢查上游是否發布了新版本，之後可以使用 `pkgctl version upgrade` 更新 `PKGBUILD`。詳細信息請參考 pkgctl-version(1)。

## 參考

- 如何正確創建補丁文件
- Arch Linux Classroom IRC 上關於如何創建 PKGBUILD 的教學日誌
- 使用 fakeroot 方式安裝軟體包

分類：​

- 關於 Arch
- 包開發

隱藏分類：​

- 使用「模板:合併」標記的頁面或章節

創建軟體包
新增話題