章 6. 構建套件

# 章 6. 構建套件

本教程文件已被重寫為另外的 Debian 維護者指導 文件，其中包含了更新的內容與更多實際例子。請使用新的教程作為主要的教程文件。

現在我們已經爲構建套件做好了準備。

## 6.1. 完整的(重)構建

爲保證完整的軟件包(重)構建能順利進行，你必須保證系統中已經安裝

- `build-essential` 套件；

- 列於 `Build-Depends` 欄位的套件(參考 節 4.1, “`control`”)；

- 列於 `Build-Depends-indep` 欄位的套件(參考 節 4.1, “`control`”)。

然後在原始碼目錄中執行以下命令：

    $ dpkg-buildpackage -us -uc

這樣會自動完成所有從原始碼套件構建二進位套件的工作，包括：

- 清理原始碼樹(`debian/rules clean`)

- 構建原始碼套件(`dpkg-source -b`)

- 構建程式(`debian/rules build`)

- 構建二進位套件(`fakeroot debian/rules binary`)

- 製作 `.dsc` 文件

- 用 dpkg-genchanges 命令製作 `.changes` 文件。

如果構建結果令人滿意，那就用 debsign 命令以你的私有 GPG 金鑰簽署 `.dsc` 檔案和 `.changes` 檔案。你需要輸入密碼兩次。 [62]

對於非本土 Debian 軟件包，比如 `gentoo`， 構建軟件包之後，你將會在上一級目錄(`~/gentoo`) 中看到下列文件：

- `gentoo_0.9.12.orig.tar.gz`

  這是原始的原始碼 tarball，最初由 `dh_make -f ../gentoo-0.9.12.tar.gz` 命令建立，它的內容與上游 tarball 相同，僅被重新命名以符合 Debian 的標準。

- `gentoo_0.9.12-1.dsc`

  這是一個從 `control` 文件生成的源代碼概要，可被 dpkg-source(1) 程序解包。

- `gentoo_0.9.12-1.debian.tar.gz`

  這個壓縮的 Tar 歸檔包含你的 `debian` 目錄內容。其他所有對於源代碼的修改都由 quilt 補丁存儲於 `debian/patches` 中。

  如果其他人想要重新構建你的套件，他們可以使用以上三個檔案很容易地完成。只需複製三個檔案，再運行 `dpkg-source -x gentoo_0.9.12-1.dsc`。 [63]

- `gentoo_0.9.12-1_i386.deb`

  這是你的二進位套件，可以使用 dpkg 程式安裝或反安裝它，就像其他套件一樣。

- `gentoo_0.9.12-1_i386.changes`

  這個文件描述了當前修訂版本軟件包中的全部變更，它被 Debian FTP 倉庫維護程序用於安裝二進制和源代碼包。它是部分從 `changelog` 和 `.dsc` 文件生成的。

  隨着你不斷完善這個軟件包，程序的行爲會發生變化，也會有更多新特性添加進來。下載你軟件包的人可以查看這個文件來快速找到有哪些變化，Debian 倉庫維護程序還會把它的內容發表至 debian-devel-changes@lists.debian.org 郵件列表。

在上傳到 Debian FTP 倉庫中前，`gentoo_0.9.12-1.dsc` 檔案和 `gentoo_0.9.12-1_i386.changes` 檔案必須用 debsign 命令簽署，其中使用你自己存放在 `~/.gnupg/` 目錄中的 GPG 私鑰。 用你的公鑰，可以令 GPG 簽名證明這些檔案真的是你的。

debsign 命令可以用來以指定 ID 的 GPG 金鑰進行簽署 （這方便了贊助(sponsor)軟體包）， 只要照著下邊在 `~/.devscripts` 中的內容：

    DEBSIGN_KEYID=Your_GPG_keyID

`.dsc` 和 `.changes` 文件中很長的數字串是其中提及文件的 SHA1/SHA256 校驗和。下載你軟件包的人可以使用 sha1sum(1) 或 sha256sum(1) 來進行覈對。如果校驗和不符，則說明文件已被損壞或偷換。

## 6.2. 自動編譯系統

Debian 支持非常多的 移植(port)，同時它有着 自動構建網絡，這個網絡在不同體繫結構的計算機上運行着 buildd 守護進程。 雖然你不需要自己做這件事情，你也應該知道在你的軟件包身上發生了什麼。讓我們來簡要地看看他們是如何爲你給多個體繫結構構建軟件包的。 [64]

對於 `Architecture: any` 的軟件包，自動編譯系統重構建它們。它確保系統中已經安裝

- `build-essential` 套件；

- 列於 `Build-Depends` 欄位的套件(參考 節 4.1, “`control`”)。

然後在原始碼目錄中執行以下命令：

    $ dpkg-buildpackage -B

這樣會自動完成從原始碼套件構建平臺依賴二進位套件的工作，包括：

- 清理原始碼樹(`debian/rules clean`)

- 構建程式(`debian/rules build`)

- 構建平臺依賴二進位套件(`fakeroot debian/rules binary-arch`)

- 使用 gpg 簽署 `.dsc` 檔案

- 使用 dpkg-genchanges 和 gpg 創建並簽署上傳用的 `.changes` 檔案

這就是你看到你的套件在其他平臺上可用的原因。

儘管通常的打包工作中 `Build-Depends-indep` 字段中列出的軟件包都需要安裝(參看 節 6.1, “完整的(重)構建”)，但是在編譯平臺依賴二進制包時它們無需在自動編譯系統上安裝。[65]通常打包和自動編譯系統的這種不同爲你指出如何考慮必須的軟件包應如何放在 `debian/control` 文件的 `Build-Depends` 或 `Build-Depends-indep` 域中(參看 節 4.1, “`control`”)。

## 6.3. debuild 命令

你可以使用 debuild 命令來進一步自動化 dpkg-buildpackage 的構建過程。參看 debuild(1)

debuild 命令會執行 lintian 命令，以在 Debian 軟體包構建結束之後進行靜態檢查。 lintian 命令可以用下邊出現在 `~/.devscripts` 檔案中的項來定製：

    DEBUILD_DPKG_BUILDPACKAGE_OPTS="-us -uc -I -i"
    DEBUILD_LINTIAN_OPTS="-i -I --show-overrides"

在普通用戶帳號中可以使用以下這樣簡單的命令清理源代碼並重構建軟件包：

    $ debuild

還可以這樣簡單地清理源代碼樹：

    $ debuild -- clean

## 6.4. `pbuilder` 套件

對於使用淨室(chroot)編譯環境來驗證編譯依賴而言，`pbuilder` 軟件包是非常有用的。[66]它確保了軟件包在不同構架上的 `sid` 發行版環境中的自動編譯器中能乾淨地編譯，避免了總是被歸類於 RC (Release Critical，影響發佈)的嚴重 FTBFS (Fails To Build From Source，從源代碼編譯失敗) Bug。[67]

我們通過以下操作來定製 `pbuilder` 軟件包。

- 設置 `/var/cache/pbuilder/result` 對當前用戶可寫。

- 創建一個對用戶可寫的目錄保存鉤子腳本，例如 ``/var/cache/pbuilder/hooks``

- 在 `~/.pbuilderrc` 或 `/etc/pbuilderrc` 中添加以下內容：

      AUTO_DEBSIGN=${AUTO_DEBSIGN:-no}
      HOOKDIR=/var/cache/pbuilder/hooks

首先使用以下命令初始化本地 `pbuilder` chroot 系統：

    $ sudo pbuilder create

如果你已經創建了源代碼包，在包含 ``foo`.orig.tar.gz`、``foo`.debian.tar.gz` 和 ``foo`.dsc` 文件的目錄中執行下面的命令來更新 `pbuilder` chroot 系統以便在其中執行構建：

    $ sudo pbuilder --update
    $ sudo pbuilder --build foo_version.dsc

新構建的無 GPG 簽名的軟件包會被以非 root 屬主放置於 `/var/cache/pbuilder/result/`。

`.dsc` 文件和 `.changes` 文件中的 GPG 簽名可以用如下方法生成：

    $ cd /var/cache/pbuilder/result/
    $ debsign foo_version_arch.changes

如果你已經更新了源代碼樹但沒有生成對應的源代碼包，在存放 `debian` 目錄的源碼目錄裏執行：

    $ sudo pbuilder --update
    $ pdebuild

你可以使用 `pbuilder --login --save-after-login` 命令登錄到這個 chroot 環境中並按照需要對其進行設定。通過 `^D` (Control-D)離開這個 shell 時環境會被保存。

最新版的 lintian 命令可以通過設置鉤子腳本 ``/var/cache/pbuilder/hooks`/B90lintian` 在 `chroot` 環境中運行。腳本內容如下：[68]

    #!/bin/sh
    set -e
    install_packages() {
            apt-get -y --allow-downgrades install "$@"
            }
    install_packages lintian
    echo "+++ lintian output +++"
    su -c "lintian -i -I --show-overrides /tmp/buildd/*.changes" - pbuilder
    # use this version if you don't want lintian to fail the build
    #su -c "lintian -i -I --show-overrides /tmp/buildd/*.changes; :" - pbuilder
    echo "+++ end of lintian output +++"

爲 `sid` 編譯軟件包需要使用 `sid` 環境。在現實中 `sid` 存在很多問題以至於你不願意將整個系統都遷移到其上。`pbuilder` 軟件包可以在這種情況下很好地解決問題。

你可能需要在 `stable` 軟體包釋出後為 `stable-proposed-updates`、`stable/updates` 等倉庫升級你維護的軟體包。[69]對於這類情況，“我正在執行 `sid` 系統”並不是你不為它們進行升級的充分理由。`pbuilder` 軟體包可以幫助你使用到相同 CPU 體系結構下幾乎所有 Debian 和 Debian 衍生版系統環境。

參見 http://www.netfort.gr.jp/~dancer/software/pbuilder.html, pdebuild(1), pbuilderrc(5), 和 pbuilder(8).

## 6.5. git-buildpackage 及其相似命令

如果你的上游對源代碼使用版本控制系統(VCS)[70]，你也應該考慮使用它們。這會使得合併和提取上游補丁更加簡單。有多個爲不同 VCS 設計的包裝腳本包來協助 Debian 軟件包構建。

- `git-buildpackage`：幫助維護 Git 倉庫中 Debian 軟件包的套件。

- `svn-buildpackage`：幫助維護 Subversion 倉庫中套件的程式。

- `cvs-buildpackage`：爲 CVS 源代碼樹設計的 Debian 軟件包腳本集。

`git-buildpackage` 的使用 在 Debian 開發者之中非常流行， 它可以使用 alioth.debian.org 上的 Git 服務器來管理 Debian 軟件包。 [71] 這個軟件包提供了許多命令來 自動化 打包操作：

- gbp-import-dsc(1): 將一個早先的 Debian 軟體包匯入到 Git 倉庫中。

- gbp-import-orig(1): 將上游 tar 檔案匯入到 Git 倉庫中。

- gbp-dch(1): 用 Git commit 資訊來生成 Debian changelog。

- git-buildpackage(1): 從 Git 倉庫中構建 Debian 軟件包。

- git-pbuilder(1): 用 pbuilder/cowbuilder 從 Git 倉庫來構建 Debian 軟件包。

這些命令使用 3 個分支來跟蹤打包操作：

- `main` 用於 Debian 軟件源碼樹。

- `upstream` 用於上游源碼樹。

- 由 `--pristine-tar` 爲上游 tarball 生成的`pristine-tar` 。[72]

你可以設置 `git-buildpackage`，通過修改 `~/.gbp.conf` 文件。參見 gbp.conf(5). [73]

## 6.6. 快速重構建

對於很大的軟件包，在調試 `debian/rules` 的過程中你可能不想每次都對整個軟件包進行重構建。僅用於測試目的，你可以不重新構建源代碼包而使用以下的方法創建 `.deb` 文件[74]：

    $ fakeroot debian/rules binary

或者可以通過以下方法驗證它是否能通過編譯：

    $ fakeroot debian/rules build

一旦完成了調試，記住要按照前面所將的正常過程重構建你的套件。你可能無法正常上傳用此種方法構建的 `.deb` 檔案。

## 6.7. 命令層級

這裏有一個簡練的總結，關於在命令層次結構中有多少用於構建軟件包的命令能夠組合到一起。做這件事情的方法非常多。

- `debian/rules` = 軟件包構建過程的專用 maintainer script

- dpkg-buildpackage = 軟件包構建之核心工具

- debuild = dpkg-buildpackage + lintian (在乾淨的環境變量下構建)

- pbuilder = Debian chroot 環境核心工具

- pdebuild = pbuilder + dpkg-buildpackage (在chroot環境中構建)

- cowbuilder = 加速 pbuilder 執行

- git-pbuilder = 命令行語法友好pdebuild (被 gbp buildpackage 使用)

- gbp = 在 Git 倉庫中管理 Debian 源碼

- gbp buildpackage = pbuilder + dpkg-buildpackage + gbp

即便像 gbp buildpackage 和 pbuilder 這樣的高級命令的應用可以確保完美的軟件包 構建環境，瞭解像 `debian/rules` 和 dpkg-buildpackage 這樣的低級命令行工具如何被它們執行也是至關重要的。

[62] 爲了連接至信任網絡，本 GPG 密鑰必須被一名 Debian 開發者簽署， 而且必須註冊到 the Debian keyring （Debian密鑰環）中。 這樣你上傳的軟件包就能被接受到 Debian 歸檔中了。 參見 Creating a new GPG key 以及 Debian Wiki on Keysigning。

[63] 你可以使用 `--skip-patches` 選項來在正常的提取操作後避免應用 `3.0 (quilt)` 源代碼包格式中的 quilt 補丁。你也可以在正常解壓後使用 `quilt pop -a` 還原這些補丁對源碼的修改。

[64] 實際中的自動構建系統包含了極爲複雜(比這裏說明的還要複雜)的體制。不過這類細節已經超出本文檔範圍。

[65] 和在 `pbuilder` 中不同，自動編譯系統使用的 `sbuild` 軟件包所維護的 chroot 不強制要求最小化的編譯系統，並可能保持很多軟件包始終安裝在其中。

[66] 由於 `pbuilder` 軟件包仍然在進化，你應當查閱最新的官方文檔來檢查實際的配置狀況。

[67] 參見 http://buildd.debian.org/ 以獲取更多關於 Debian 軟件包 auto-building 的信息。

[68] 此處默認 `HOOKDIR=/var/cache/pbuilder/hooks`。你可以在 `/usr/share/doc/pbuilder/examples` 目錄中找到很多鉤子腳本的例子。

[69] 升級你的 `stable` 套件有規定限制。

[70] 參見 Version control systems 以獲取更多信息。

[71] Debian wiki Alioth 這裏說明瞭 如何使用 alioth.debian.org 服務。

[72] `--pristine-tar` 選項會呼叫 pristine-tar 命令，它能利用一個很小的二進位制差量檔案以及在版本控制系統中某個分支內儲存的上游檔案內容（分支名通常為 `upstream`）重新生成與上游 tarball 完全相同的一份副本。

[73] 這裏有一些給高級讀者參考的網頁資源。

- 用 git-buildpackage (`/usr/share/doc/git-buildpackage/manual-html/gbp.html`) 構建 Debian 軟件包

- debian packages in git

- Using Git for Debian Packaging

- git-dpm: Debian packages in Git manager

[74] 常規情形下被配置好的環境變數在此時不會被自動設定。永遠不要將使用這個 快速 方法構建的軟體包上傳到任何地方。

章 5. `debian` 目錄下的其他檔案 |  | 章 7. 檢査套件中的錯誤