章 2. 第一步

# 章 2. 第一步

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

讓我們嘗試創建一個自己的軟件包(或者，“收養”一個已存在的軟件包則更好)。

## 2.1. Debian 軟件包構建流程

如果你要基於某個上遊程序構建軟件包，那麼典型的Debian軟件包構建流程就會包含生成幾個特定的文件，如下：

- 獲取上游軟件的拷貝，通常爲壓縮過的tar格式。

  - ``package`-`version`.tar.gz`

- 在上遊程序的 `debian` 目錄下添加 Debian 特定的打包修改，並以 `3.0 (quilt)` 格式創建一個非本地源碼包。(也就是指用於構建 Debian 軟件包的輸入文件集合)

  - ``package`_`version`.orig.tar.gz`
  - ``package`_`version`-`revision`.debian.tar.gz` [4]
  - ``package`_`version`-`revision`.dsc`

- 從 Debian 源碼包構建 Debian 二進制包；二進制包的格式通常是`.deb` (或者 `.udeb`，Debian Installer 專用)

  - ``package`_`version`-`revision`_`arch`.deb`

請注意，在 Debian 軟件包文件名中，分隔 ``package`` 和 ``version`` 的字符從 tarball 名稱的 `-` (連字符)換成了 `_` (下劃線)。

在上述的文件名中，將 ``package`` 部分替換爲 package name， 將 ``version`` 部分替換爲 upstream version， 將``revision`` 部分替換爲 Debian revision，以及將 ``arch`` 部分替換爲 package architecture，根據 Debian 方針手冊。 [5]

本大綱中的每一步都會在後續的章節中輔以詳細的例子進行解釋。

## 2.2. 選擇你的程式

可能你已經選好了要製作的軟件包。第一件要做的事是檢查它是否已經存在於發行版倉庫中了，參考方法如下：

- aptitude 命令

- the Debian packages 頁面

- the Debian Package Tracker 頁面

如果軟件包已經存在，直接安裝就好了！:-) 如果它是被 拋棄(orphaned) 的——也就是說它的維護者被設置爲 Debian QA Group，那麼你可以嘗試接手維護它。你也可以“收養”維護者發出“Request for Adoption”(RFA)請求的軟件包。[6]

軟件包歸屬狀態有這幾種：

- wnpp-alert 命令，來自 `devscripts` 軟件包

- Work-Needing and Prospective Packages

- Debian Bug report logs: Bugs in pseudo-package `wnpp` 於 `unstable`

- Debian Packages that Need Lovin'

- Browse `wnpp` bugs based on debtags

作爲旁註必須指出，Debian 已經擁有了絕大多數類型軟件的軟件包，倉庫中軟件包的數量也遠遠超過了有上傳權限的貢獻者的數量。因此，爲已經在倉庫中的軟件包貢獻力量是非常受其他開發者歡迎的(且更容易獲得 sponsorship)[7]。你可以通過非常多的方式來實現這一目的：

- 接手被拋棄而仍然被很多人使用的套件。

- 加入 打包小組。

- 爲某些常用的套件分類 Bug。

- 在需要時準備 QA 或 NMU 上傳。

如果你有能力“領養”那個軟體包，那就先下載 (使用 `apt-get source `packagename`` 或其他類似的工具)並分析它的原始碼。這篇文件不會詳細說明如何領養軟體包，不過幸運的是，領養軟體包時，打包的起始工作已經有人完成，接手的工作應比從頭開始輕鬆得多。儘管如此也請您不要輕敵，請繼續閱讀，下面給出的建議會對你很有幫助。

如果你要製作的套件是全新的，並且希望它出現在 Debian 中，請按照以下的步驟進行：

- 首先，你必須知道這個軟件的可用性，並且需要試用一段時間。

- 一定要在 Work-Needing and Prospective Packages 上仔細檢視，以確定並沒有其他人已經開始相關的工作。如果沒有的話，則可以提交一份 ITP (Intent To Package，打包意向) Bug 報告給 `wnpp` 虛包 (可以使用 reportbug)。如果你看到已經有人在處理相關事宜，則在有需要的情況下再聯絡他(們)。如果他(們)不需要你的幫助，那就尋找其他你感興趣，而且沒有人維護的軟體包咯。

- 該軟件 必須有一個許可證。

  - 對於 `main` 類的軟件， Debian 方針要求它 完全兼容 Debian Free Software Guidelines （Debian 自由軟件準則） (DFSG) 並且 不要求用 `main` 類以外的軟件來編譯或執行。這是最理想的狀況。

  - 對於 `contrib` 類的軟件，其許可證必須滿足 DFSG 的全部條件，但可以依賴於 `main` 之外的軟件包以完成編譯或運行。

  - 對於 `non-free` 類的軟件，其許可證可以不滿足 DFSG 中的一些條件，但至少 必須是可分發的。

  - 如果你不清楚你的軟體應該分入哪一類，則把許可證文本發送到 debian-legal@lists.debian.org 請他人提出意見。

- 程式 不能 給 Debian 系統帶來安全或維護問題。

  - 程式應當帶有良好的文件，最好是原始碼也容易理解 （比如，不混亂）。

  - 你應該與程序的作者取得聯繫問一下他是否認爲程序應當被打包，以及他是否對 Debian 友好。能夠詢問作者關於程序的任何問題是非常重要的，所以不要嘗試打包一個無人維護的軟件。

  - 程序一定 不應該 setuid 到 root 。更好的情況是它不 setuid 或 setgid 到任何用戶或組。

  - 程序不應該是守護進程，也不應該進入 `*/sbin` 目錄或者以 root 打開任何端口。

當然，這些都是為了安全，並試圖避免你在，比如 setuid 守護程序等問題上犯錯誤而激怒了使用者 ... 當你在打包方面有了更多經驗時，就能夠處理這樣的軟體包了，不必著急。

我們鼓勵你，作爲一個新維護人員，選擇易於打包和維護的軟件包，而不鼓勵選擇複雜的軟件包。

- 簡單軟件包

  - 單二進制軟件包，arch = all （比如像壁紙那樣的資料集）

  - 單二進制軟件包，arch = all （用解釋型語言編寫的可執行腳本文件，比如 POSIX shell）

- 中等複雜軟件包

  - 單二進制軟件包，arch = any （用C/C++等語言編寫的 ELF 二進制可執行文件）

  - 複合二進制軟件包，arch = any + all （包含ELF二進制可執行程序+文檔的軟件包）

  - 既不是 `tar.gz` 也不是 `tar.bz2` 格式的上有源代碼

  - 源代碼中包含不可分發的內容。

- 高複雜軟件包

  - 被其他軟件包使用的解釋器模塊包

  - 被其他軟件包使用的一般ELF庫文件包

  - 複合二進制的軟件包，包含ELF庫文件包

  - 多上游的源碼包

  - 內核模塊軟件包

  - 內核補丁軟件包

  - 包含冷門維護者腳本的軟件包

打包高複雜軟件包並非難如登天，但需要更多知識。你應該針對每一個複雜特性來搜尋針對性的指南。比如，一些語言有它們自己的子策略文檔：

- Perl policy

- Python policy

- Java policy

還有一句拉丁諺語：fabricando fit faber （熟能生巧）。我們 強烈 建議你在閱讀這篇教程的時候，用一個簡單的軟體包來對所有的 Debian 打包步驟進行實驗。跟隨下邊的步驟您就可以建立一個微不足道的軟體包 `hello-sh-1.0.tar.gz` ，而且這會是一個非常好的開端：[8]

    $ mkdir -p hello-sh/hello-sh-1.0; cd hello-sh/hello-sh-1.0
    $ cat > hello <<EOF
    #!/bin/sh
    # (C) 2011 Foo Bar, GPL2+
    echo "Hello!"
    EOF
    $ chmod 755 hello
    $ cd ..
    $ tar -cvzf hello-sh-1.0.tar.gz hello-sh-1.0

## 2.3. 獲得程式，並且試用它

第一件要做的事就是找到並下載原始的源代碼。我們假定你已經從作者的主頁上找到了它的源代碼。Unix 下的自由軟件源代碼通常是以 tar+gzip 格式(擴展名爲 `.tar.gz`)或 tar+bzip2 格式(擴展名爲 `.tar.bz2`)或tar+xz (擴展名爲`.tar.xz`)的形式提供的。通常歸檔文件中包含了一個名爲 ``package`-`version`` 的子目錄，裏麪包含了全部的源代碼。

如果最新版本的原始碼可透過像 Git，Subversion，CVS 這樣的版本控制系統獲得的話，你可以用 `git clone` ， `svn co`, 或 `cvs co` 來下載它，然後將它重新打包壓縮為 tar+gzip 格式， 同時別忘了 `--exclude-vcs` 選項喲。

如果你的程序源代碼是以其他形式提供的(比如文件名以 `.Z` 或 `.zip` 結尾[9])，則使用合適的工具將其解包，再重新打包。

如果你的程序源代碼中包含一些不符合DFSG的內容，你應當解包後移除它們，再以添加了 `dfsg` 的上游版本號重新打包。

作爲示例，我將使用一個名爲 gentoo 的程序，它是一個 GTK+ 文件管理器。[10]

在你的用戶主目錄下創建一個子目錄，命名爲 `debian` 或 `deb` 或其他你喜歡且合適的名字(本例中使用 `~/gentoo`)。把下載好的歸檔文件放在其中並解包(使用 `tar xzf gentoo-0.9.12.tar.gz` 命令)。要確定解包過程中沒有發生錯誤，即便是有一點 不恰當 也不行，因爲在別人的系統上解包這些文件時，可能他們的工具並不忽略這些反常的現象，於是就會出現問題。在你的終端屏幕上，應該看到如下的情形。

    $ mkdir ~/gentoo ; cd ~/gentoo
    $ wget http://www.example.org/gentoo-0.9.12.tar.gz
    $ tar xvzf gentoo-0.9.12.tar.gz
    $ ls -F
    gentoo-0.9.12/
    gentoo-0.9.12.tar.gz

現在又有了一個新的子目錄，名爲 `gentoo-0.9.12`。進入該目錄並 徹底 讀完其中的文檔。通常情況下這些文檔被命名爲 `README*`、`INSTALL*`、`*.lsm` 或 `*.html`。你必須找到關於如何正確編譯和安裝程序的指導(最可能的是他們會默認你希望把程序安裝到 `/usr/local/bin` 目錄；但事實上你不能那樣做，詳細的內容稍後將在 節 3.3, “把文件安裝到目的位置” 中說明)。

開始打包時原始碼目錄應當是絕對乾淨(原始)的，或者直接使用剛剛解壓縮得到的原始碼。

## 2.4. 簡易構建系統

帶有 `Makefile` 文件的簡單程序可以很容易地使用 `make` 來編譯。[11] 其中的一些還支持 `make check`，這可以完成一系列自檢。編譯好後可以使用 `make install` 來將程序安裝到目標目錄。

現在嘗試編譯和運行你的程式，確保它工作正常，且在安裝和運行時不會導致其他問題。

你還可以運行 `make clean` (或更好的 `make distclean`)來清理編譯目錄。有時還會帶有 `make uninstall` 用以反安裝已經安裝了的檔案。

## 2.5. 常见的可移植的構建系統

非常多的自由軟件是使用 C 和 C++ 語言編寫的。其中的有很多使用 Autotools 或 CMake 來使其可以在不同平臺上移植。這些工具首先用於生成 `Makefile` 和其他必須的源文件，然後這些程序可以使用正常的 `make; make install` 來編譯和安裝。

Autotools 是 GNU 編譯系統工具，包括 Autoconf、Automake、Libtool 和 gettext。你可以通過 `configure.ac`、`Makefile.am` 和 `Makefile.in` 等文件來識別這種類型的源代碼。[12]

使用 Autotools 的第一步是在上游作者在代碼中運行 `autoreconf -i -f` ，然後把生成的文件同源代碼一起分發。

    configure.ac-----+-> autoreconf -+-> configure
    Makefile.am -----+        |      +-> Makefile.in
    src/Makefile.am -+        |      +-> src/Makefile.in
                              |      +-> config.h.in
                          automake
                          aclocal
                          aclocal.m4
                          autoheader

編輯 `configure.ac` 和 `Makefile.am` 等檔案需要一些關於 autoconf 和 automake 的知識。參考 `info autoconf` 和 `info automake`。

使用 Autotools 的第二步是用戶獲得分發的源代碼後在源碼目錄下運行 `./configure && make` 來將其編譯成爲 `binary` (二進制可執行程序)。

    Makefile.in -----+                +-> Makefile -----+-> make -> binary
    src/Makefile.in -+-> ./configure -+-> src/Makefile -+
    config.h.in -----+                +-> config.h -----+
                     |
      config.status -+
      config.guess --+

你可以改變 `Makefile` 文件中的許多設置，比如修改默認的文件安裝位置(使用 `./configure --prefix=/usr`)。

儘管不是必須的：你還可以使用 `autoreconf -i -f` 來更新 `configure` 和其他相關文件，這樣做有可能提高源代碼的兼容性。 [13]

CMake 是另一個可選的構建系統，你可以通過 `CMakeLists.txt` 文件來識別使用它的源代碼。

## 2.6. 套件名稱和版本

如果上游源代碼以像 `gentoo-0.9.12.tar.gz` 的形式分發，你可以用 `gentoo` 作爲(源代碼) 軟件包名 ，並用 `0.9.12` 作爲 上游版本。 它們會被 `debian/changelog` 這個文件用到；該文件一會會在 節 4.3, “`changelog`” 部分詳細描述。

雖然此法在大部分情況下能顯靈，但你仍需要根據 Debian 政策（Debian Policy）以及約定俗成的做法來調整 軟體包名 和 上游版本 。

在 軟體包名 裡只能含有 小寫字母 (`a-z`), 數字 (`0-9`), 加號 (`+`) 和 減號 (`-`) ， 以及 點號 (`.`)。 軟體包名最短長度兩個字元；它必須以字母開頭；它不能與倉庫軟體包名發生衝突。還有，把軟體包名的長度控制在 30 字元以內是明智之舉。 [14]

如果上游在它的名稱中使用了一些通用術語比如 `test-suite`， 那麼將其重命名，以顯式指明其內容並避免命名空間污染。 [15]

你應該讓 upstream version（上游版本號） 只包含字母和數字 (`0-9A-Za-z`), 以及加號 (`+`), 波浪號 (`~`), 還有 點號(`.`)。它必須以數字開頭 (`0-9`)。 [16] 如果可能的話，最好把它的長度控制在8字元以內。 [17]

如果上游不使用像 `2.30.32` 這樣的常規版本格式，而是用類似 `11Apr29` 這樣的日期作為版本，類似於隨機的代號字串，或者以VCS的雜湊值作為版本號的一部分，那麼請確認將其從 upstream version 中移除。 為此作出的改動資訊可以記錄在 `debian/changelog` 檔案中。 如果你需要發明一個版本字串，請使用 `YYYYMMDD` 這個格式作為上游版本，比如 `20110429` 。這會確保 dpkg 在升級軟體包時能夠正確解讀新版本。 如果需要確保未來能夠平滑過渡到類似 `0.1` 這樣的版本號的話，那就請使用 `0~YYMMDD` 格式作為上游版本，例如 `0~110429` 。

版本字符串 [18] 可以用 dpkg(1) 來進行比較：

    $ dpkg --compare-versions ver1 op ver2

版本比較規則可以總結爲以下幾點：

- 字符串會被從頭到尾進行比較。

- 字母比數字大。

- 數字作爲整數進行比較。

- 字母按照 ASCII 編碼順序進行比較。

- 對於點號 (`.`)，加號 (`+`)，以及波浪號 (`~`) 則要應用特殊規則，具體如下：

  `0.0` < `0.5` < `0.10` < `0.99` < `1` < `1.0~rc1` < `1.0` < `1.0+b1` < `1.0+nmu1` < `1.1` < `2.0`

有一種比較棘手的情況，當上游釋出 `gentoo-0.9.12-ReleaseCandidate-99.tar.gz` 作爲 `gentoo-0.9.12.tar.gz` 的預發佈版本時，就需要確保升級工作妥當進行：重命名該上游源代碼爲 `gentoo-0.9.12~rc99.tar.gz`.

## 2.7. 設置 dh_make

首先我們設置兩個 環境變量，`$DEBEMAIL` 和 `$DEBFULLNAME`，這樣能使使大多數 Debian 維護工具能夠正確識別你用於維護軟件包的姓名和電子郵件地址。[19]

    $ cat >>~/.bashrc <<EOF
    DEBEMAIL="your.email.address@example.org"
    DEBFULLNAME="Firstname Lastname"
    export DEBEMAIL DEBFULLNAME
    EOF
    $ . ~/.bashrc

## 2.8. 初始化外來 Debian 軟件包

一般的 Debian 軟件包是由上遊程序產生的 外來 Debian 軟件包。 若你想要用上游源代碼 `gentoo-0.9.12.tar.gz` 創建一個外來 Debian 軟件包，你可以爲它創建一個初始的外來 Debian 軟件包，通過如下方法調用 dh_make 命令：

    $ cd ~/gentoo
    $ wget http://example.org/gentoo-0.9.12.tar.gz
    $ tar -xvzf gentoo-0.9.12.tar.gz
    $ cd gentoo-0.9.12
    $ dh_make -f ../gentoo-0.9.12.tar.gz

當然，請用你原始源碼歸檔的名字來替換 filename (文件名)。 [20] 詳情請參見 dh_make(8) 。

你會看到一些輸出，詢問你想要建立什麼型別的軟體包。這裡的 Gentoo 被規劃為一個單一二進位制包——它僅僅產生一個二進位制包， 亦即單個 `.deb` 檔案——於是我們就選擇第一項 (按 `s` 鍵)， 認真閱讀螢幕上的輸出資訊， 然後按 ``ENTER`` 鍵來確認。 [21]

執行 dh_make 後，上一級目錄中自動創建了一份上游 tarball 的副本，名爲 `gentoo_0.9.12.orig.tar.gz`，這個文件和稍後介紹的 `debian.tar.gz` 在一起滿足了 Debian 非本地源代碼包的要求。

    $ cd ~/gentoo ; ls -F
    gentoo-0.9.12/
    gentoo-0.9.12.tar.gz
    gentoo_0.9.12.orig.tar.gz

請注意 `gentoo_0.9.12.orig.tar.gz` 這個文件名的兩個關鍵特點：

- 軟件包名稱和版本是以字符 `_` （下劃線）分隔的。

- `.tar.gz` 擴展名前插有 `.orig`。

你應該可以注意到 `debian` 目錄下有了許多模板文件。這些文件將在 章 4, `debian` 目錄中的必須內容 和 章 5, `debian` 目錄下的其他檔案 中一一解釋。你還應該明白，打包沒辦法變成全自動的過程。你還需要按照 章 3, 修改原始碼 中的方法來爲 Debian 修改軟件包。此後，你還要按照 章 6, 構建套件 中敘述的合適的方法來構建 Debian 軟件包，並按照 章 7, 檢査套件中的錯誤 中的方法進行測試，最終依照 章 9, 上傳套件 的介紹將其上傳。本教程將對所有的這些步驟進行解釋。

如果你在修改過程中不小心刪除或弄壞了某些模板檔案，你可以使用 dh_make 加上 `--addmissing` 參數來將其還原。

更新一個已存在的軟件包可能比較複雜，因爲它可能使用了舊技術。在學習基本功的階段，請只創建全新的軟件包；稍後的 章 8, 更新套件中會有更細緻的講解。

請注意，原始碼中不必包含任何在 節 2.4, “簡易構建系統” 或 節 2.5, “常见的可移植的構建系統” 中談論到的編譯系統。 就算原始碼包僅僅是一組影象之類的也可以，這時候這些檔案的安裝可以用 `debhelper` 的配置檔案來搞定，比如 `debian/install` (參見 節 5.11, “`install`”)。

[4] 對於舊式的 `1.0` 格式非本地 Debian 源碼包，應當使用 ``package`_`version`-`revision`.diff.gz` 。

[5] 參見 5.6.1 "Source", 5.6.7 "Package", 以及 5.6.12 "Version"。 package architecture 遵循 Debian Policy Manual, 5.6.8 "Architecture" 並且會在軟件包構建的過程中被自動分配。

[6] 參見 Debian Developer's Reference 5.9.5. "Adopting a package".

[7] 當然了，總有值得打包的新軟件。

[8] 不用擔心失蹤的 `Makefile`。你可以參照 節 5.11, “`install`” ，簡單地通過 debhelper 來安裝 hello 程序，或者修改上游源代碼來添加帶有`install`目標的新`Makefile`，參照章 3, 修改原始碼

[9] 當檔案副檔名不足以判斷檔案類型時，可以使用 file 命令來判斷。

[10] 需要注意的是，這個程序已經被打包好了。當前的版本 使用 Autotools 作爲其構造(build structure)，並且已經和下邊的例子大不相同，下邊的例子基於版本 0.9.12 。

[11] 許多新時代的程式都配有一個叫做 `configure` 的指令碼。執行它的時候會生成一個為你的計算機專門定製的 `Makefile` 。

[12] Autotools 這個龐然大物顯然已經超出本教程的討論範圍，畢竟本文主要提供關鍵字和提示。如果你需要使用 Autotools ，請認真研讀 Autotools Tutorial 以及 `/usr/share/doc/autotools-dev/README.Debian.gz` 的本地副本。

[13] 你可以用 `dh-autoreconf` 軟件包來將這個過程自動化。參見 節 4.4.3, “定製 `rules` 檔案”.

[14] 在 aptitude 工具中，軟件包名字段的默認最大長度爲 30。 而對於 90% 以上的軟件包來說，軟件包名都少於 24 個字符。

[15] 如果你遵循 Debian Developer's Reference 5.1. "New packages"， 那麼在 ITP 過程中很容易遇到這樣的問題。

[16] 這一條更嚴格的規則能幫助你避免混淆文件名。

[17] aptitude 命令的版本字段默認長度爲10。其中通常 Debian 修訂號和前置的連字符會消耗2個位置。對於 80% 以上的軟件包來說，上游版本小於8字符，Debian 修訂號小於2字符。對於 90% 以上的軟件包來說，上游版本小於10字符，Debian 修訂號小於3字符。

[18] 版本字符串可以是 upstream version (``version``), Debian revision (``revision``), 或者 version (``version`-`revision``)。 關於 Debian 修訂號如何增長的信息，請參見 節 8.1, “新的 Debian 版本”Debian revision 。

[19] 以下默認你以 Bash 作爲登陸 shell。如果你使用其他的 shell，例如 Z shell，那就使用它們的配置文件代替這裏提到的 `~/.bashrc`。

[20] 如果上游原始碼已經提供了有內容的 `debian` 目錄，那麼帶上引數 `--addmissing` 來執行dh_make 命令。 新的原始碼包格式 `3.0 (quilt)` 的魯棒性(Robust)已經足夠優秀，以不至於輕易損壞。 另外，你可能需要修改上游提供的內容，以滿足你的 Debian 軟體包之需。

[21] 此處有這幾種選擇： `s` 代表單一二進制包， `i` 代表獨立於體繫結構的軟件包， `m` 代表複合二進制包， `l` 代表庫文件包，`k` 代表內核模塊包， `n` 代表內核補丁包， `b` 代表 `cdbs` 軟件包。本教程專注於使用 dh 命令 (來自 `debhelper` 軟件包) 來創建單一二進制包，但 也會涉及到如何用它來創建 獨立於體繫結構 或 複合二進制軟件包。軟件包 `cdbs` 提供了 另一套可以代替 dh 命令的基礎打包腳本，不過對它的描述已經超出了我們的討論範圍。

章 1. 從一條正確的路開始 |  | 章 3. 修改原始碼