章 10. 高階打包

內容目錄

10.1. Historical perspective
10.2. Current trends
10.3. Note on build system
10.4. 持續整合
10.5. 自主生成 (Bootstrapping)
10.6. 編譯強化
10.7. 可重現的構建
10.8. Substvar
10.9. 程式庫套件
10.10. 多體系架構
10.11. Debian 二進位制套件的拆分
10.12. 拆包的場景和例子
10.13. Multiarch library path
10.14. Multiarch header file path
10.15. Multiarch *.pc file path
10.16. 程式庫符號
10.17. Library package name
10.18. 程式庫變遷
10.19. binNMU 安全
10.20. 除錯資訊
10.21. -dbgsym package
10.22. debconf

Let’s describe advanced topics on Debian packaging.

Let me oversimplify historical perspective of Debian packaging practices focused on the non-native packaging.

Debian was started in 1990s when upstream packages were available from public FTP sites such as Sunsite. In those early days, Debian packaging used Debian source format currently known as the Debian source format 1.0:

  • The Debian source package ships a set of files for the Debian source package.

    • package_version.orig.tar.gz : symlink to or copy of the upstream released file.
    • package_version-revision.diff.gz : One big patch for Debian modifications.
    • package_version-revision.dsc : package description.
  • Several workaround approaches such as dpatch, dbs, or cdbs were deployed to manage multiple topic patches.

The modern Debian source format 3.0 (quilt) was invented around 2008 (see ProjectsDebSrc3.0):

  • The Debian source package ships a set of files for the Debian source package.

    • package_version.orig.tar.?z : symlink to or copy of the upstream released file.
    • package_version-revision.debian.tar.?z : tarball of debian/ for Debian modifications.

      • The debian/source/format file contains 3.0 (quilt).
      • Optional multiple topic patches are stored in the debian/patches/ directory.
    • package_version-revision.dsc : package description.
  • The standardized approach to manage multiple topic patches using quilt(1) is deployed for the Debian source format 3.0 (quilt).

Most Debian packages adopted the Debian source formats 3.0 (quilt) and 3.0 (native).

Now, the git(1) is popular with upstream and Debian developers. The git and its associated tools are important part of the modern Debian packaging workflow. This modern workflow involving git will be mentioned later in 章 11, Packaging with git.

Current Debian packaging practices and their trends are moving target. See:

  • Debian Trends” — Hints for De facto standard of Debian practices

    • Build systems: dh
    • Debian source format: 3.0 (quilt)
    • VCS: git
    • VCS Hosting: salsa
    • Rules-Requires-Root: adopted, fakeroot
    • Copyright format: DEP-5
  • debhelper-compat-upgrade-checklist(7) manpage — Upgrade checklist for debhelper
  • DEP - Debian Enhancement Proposals — Formal proposals to enhance Debian

You can also search entire Debian source code data by yourself, too.

Auto-generated files of the build system may be found in the released upstream tarball. These should be regenerated when Debian package is build. E.g.:

  • dh $@ --with autoreconf should be used in the debian/rules if Autotools (autoconf + automake) are used.

Some modern build system may be able to download required source codes and binary files from arbitrary remote hosts to satisfy build requirements. Don’t use this download feature. The official Debian package is required to be build only with packages listed in Build-Depends: of the debian/control file.

The dh_auto_test(1) command is a debhelper command that tries to automatically run the test suite provided by the upstream developer during the Debian package building process.

The autopkgtest(1) command can be used after the Debian package building process. It tests generated Debian binary packages in the virtual environment using the debian/tests/control RFC822-style metadata file as continuous integration (CI). See:

您可以在 Debian 系統上探索使用不同的持續整合系統。

Debian cares about supporting new ports or flavours. The new ports or flavours require bootstrapping operation for the cross-build of the initial minimal native-building system. In order to avoid build-dependency loops during bootstrapping, the build-dependency needs to be reduced using the DEB_BUILD_PROFILES environment variable.

See Debian wiki: BuildProfileSpec.

[提示]提示

If a core package foo build depends on a package bar with deep build dependency chains but bar is only used in the test target in foo, you can safely mark the bar with <!nocheck> in the Build-depends of foo to avoid build loops.

The compiler hardening support spreading for Debian jessie (8.0) demands that we pay extra attention to the packaging.

您應當詳細閱讀下列參考內容。

debmake 命令會對 debian/rules 檔案中按需新增 DEB_BUILD_MAINT_OPTIONSDEB_CFLAGS_MAINT_APPENDDEB_LDFLAGS_MAINT_APPEND 的專案(參見 章 5, Simple packagingdpkg-buildflags(1))。

為了做到套件可重現的構建,這裡給出一些相關的建議。

Reproducible builds are important for security and quality assurance. They allow independent verification that no vulnerabilities or backdoors have been introduced during the build process.

dpkg-genbuildinfo(1) 生成的控制檔案 source-name_source-version_arch.buildinfo 記錄了構建環境資訊。參見 deb-buildinfo(5)

debian/control 也定義了套件的依賴關系,其中變數替換機制”(substvar)的功能可以用來將套件維護者從追蹤(大多數簡單的)套件依賴的重複勞動中解放出來。請參見 deb-substvars(5)。

debmake 命令支援下列變數替換指令:

  • ${misc:Depends},可用於所有二進位制套件
  • ${misc:Pre-Depends},可用於所有 multiarch 套件
  • ${shlibs:Depends},可用於所有含有二進位制可執行檔案或程式庫的套件
  • ${python:Depends},可用於所有 Python 套件
  • ${python3:Depends},可用於所有 Python3 套件
  • ${perl:Depends},用於所有 Perl 套件
  • ${ruby:Depends},用於所有 Ruby 套件

For the shared library, required libraries found simply by objdump -p /path/to/program | grep NEEDED are covered by the shlib substvar.

For Python and other interpreters, required modules found simply looking for lines with import, use, require, etc., are covered by the corresponding substvars.

對其它沒有部署屬於自己範疇內的變數替換機制的情況,misc 變數替換佔位符通常用來覆蓋對應的依賴替換需求。

對 POSIX shell 程式來說,並沒有簡單的辦法來驗證其依賴關係,substvar 的變數替換也無法自動得出它們的依賴。

對使用動態載入機制,包括 GObject introspection 機制的程式庫和模組來說,現在沒有簡單的方法可以檢查依賴關係,變數替換機制也無法自動推匯出所需的依賴。

打包軟體程式庫需要您投入更多的工作。下面有一些打包軟體程式庫的提醒和建議:

在打包共享程式庫軟體之前,請查閱:

如需研究其歷史背景,請參見:

Debian wheezy(7.0,2013年5月)在 dpkgapt 中引入了對跨架構二進位制套件安裝的多架構支援(特別是 i386 架構和 amd64 架構,但也支援其它的組合),這部分內容值得我們額外關注。

您應當詳細閱讀下列參考內容。

多架構支援使用三元組(<triplet>)的值,例如 i386-linux-gnux86_64-linux-gnu;它們出現在共享連結程式庫的安裝路徑中,例如 /usr/lib/<triplet>/,等等。

  • 三元組 <triplet> 的值由 debhelper 指令碼隱性提前設定好,套件維護者無需擔心。
  • 不過,在 debian/rules 檔案中用於 override_dh_* 目標的三元組 <triplet> 值需要由維護者手動進行顯性設定。三元組 <triplet> 的值可由 $(DEB_HOST_MULTIARCH) 變數在 debian/rules 檔案中取得到,具體方法如下:

    DEB_HOST_MULTIARCH = $(shell dpkg-architecture -qDEB_HOST_MULTIARCH)
    ...
    override_dh_install:
    	mkdir -p package1/lib/$(DEB_HOST_MULTIARCH)
    	cp -dR tmp/lib/. package1/lib/$(DEB_HOST_MULTIARCH)

參見:

對行為良好的構建系統來說,對 Debian 二進位制包的拆分可以由如下方式實現。

  • 為所有二進位制套件在 debian/control 檔案中建立對應的二進位制套件條目。
  • 在對應的 debian/二進位制套件名.install 檔案中列出所有檔案的路徑(相對於 debian/tmp 目錄)。

請檢視本指南中相關的例子:

An intuitive and flexible method to create the initial template debian/control file defining the split of the Debian binary packages is accommodated with the -b option. See 節 16.2, “debmake -b.

對於下面這樣的上游原始碼範例,我們在這裡給出使用 debmake 處理時一些典型的 multiarch 套件拆分的場景和做法:

  • 一個程式庫原始碼 libfoo-1.0.tar.gz
  • 一個軟體工具原始碼 bar-1.0.tar.gz,軟體由編譯型語言編寫
  • 一個軟體工具原始碼 baz-1.0.tar.gz,軟體由解釋型語言編寫
二進位制套件型別Architecture:Multi-Arch:套件內容

libfoo1

lib*

any

same

共享程式庫,可共同安裝

libfoo-dev

dev*

any

same

共享程式庫標頭檔案及相關開發檔案,可共同安裝

libfoo-tools

bin*

any

foreign

執行時支援程式,不可共同安裝

libfoo-doc

doc*

all

foreign

共享程式庫文件

bar

bin*

any

foreign

編譯好的程式檔案,不可共同安裝

bar-doc

doc*

all

foreign

程式的配套文件檔案

baz

script

all

foreign

解釋型程式檔案

Debian policy requires to comply with the Filesystem Hierarchy Standard (FHS), version 3.0”, with the exceptions noted in File System Structure.

The most notable exception is the use of /usr/lib/<triplet>/ instead of /usr/lib<qual>/ (e.g., /lib32/ and /lib64/) to support a multiarch library.


對基於 Autotools 且由 debhelper (compat>=9)管理的套件來說,這些路徑設定已由 dh_auto_configure 命令自動處理。

對於其它使用不支援的構建系統的套件,您需要按照下面的方式手動調整安裝路徑。

  • If ./configure is used in the override_dh_auto_configure target in debian/rules, make sure to replace it with dh_auto_configure -- while re-targeting the install path from /usr/lib/ to /usr/lib/$(DEB_HOST_MULTIARCH)/.
  • 請在 debian/foo.install 檔案中將所有出現的 /usr/lib/ 字串替換為 /usr/lib/*/

所有啟用多架構的套件安裝至相同路徑的檔案必須內容完全相同。您必須小心處理,避免資料位元組序或者壓縮演算法等等問題帶來的檔案內容差異。

位於預設路徑 /usr/lib//usr/lib/<triplet>/ 的共享程式庫可被自動載入。

對位於其它路徑的共享程式庫,必須使用 pkg-config 命令設定 GCC 選項 -l 以正確進行載入。

在支援多架構的 Debian 系統上,GCC 預設會同時包含、使用 /usr/include//usr/include/<triplet>/ 下的標頭檔案。

如果標頭檔案不在這些路徑中,必須使用 pkg-config 命令設定 GCC 的 -I 引數以使得“#include <foo.h>”正常工作。


為程式庫檔案使用 /usr/lib/<triplet>/套件名/ 路徑可幫助上游維護者對使用 /usr/lib/<triplet> 的多架構系統和使用 /usr/lib<qual>/ 的雙架構系統使用相同的安裝指令碼。[20]

使用包含 packagename 的檔案路徑也使得在同一系統上同時安裝多個架構的開發程式庫成為可能。

packagename 用來取得系統上已安裝程式庫的資訊。它在 *.pc 檔案中儲存配置引數,用來設定 GCC 的 -I-l 選項。


Debian lenny(5.0,2009年5月)中引入的 dpkg 符號支援可以幫助我們管理同一共享鏈接程式庫套件的向後 ABI 相容性(backward ABI compatibility)。二進位制套件中的 DEBIAN/symbols 檔案提供了每個符號及其對應的最小版本號。

一個極其簡化的軟體程式庫打包流程大概如下所示。

  • Extract the old DEBIAN/symbols file of the immediate previous binary package with the dpkg-deb -e command.

    • 或者,mc 命令也可以用來解壓得到 DEBIAN/symbols 檔案。
  • 將其複製為 debian/binarypackage.symbols 檔案。

    • 如果這是第一次打包的話,可以只建立一個空檔案。
  • 構建二進位制套件。

    • 如果 dpkg-gensymbols 命令警告添加了新的符號的話:

      • Extract the updated DEBIAN/symbols file with the dpkg-deb -e command.
      • 將其中的 Debian 修訂版本號,例如 -1,從檔案中去除。
      • 將其複製為 debian/binarypackage.symbols 檔案。
      • 重新構建二進位制套件。
    • 如果 dpkg-gensymbols 命令不報和新連結符號有關的警告:

      • 您已完成了共享程式庫的打包工作。

如需瞭解詳細資訊,您應當閱讀下列第一手參考資料。

  • 8.6.3 The symbols system” of the Debian Policy Manual
  • dh_makeshlibs(1) manapage
  • dpkg-gensymbols(1) manapage
  • dpkg-shlibdeps(1) manapage
  • deb-symbols(5) manapage

您也應當檢視:

[提示]提示

For C++ libraries and other cases where the tracking of symbols is problematic, follow 8.6.4 The shlibs system of the Debian Policy Manual, instead. Please make sure to erase the empty debian/binarypackage.symbols file generated by the debmake command. For this case, the DEBIAN/shlibs file is used.

我們考慮 libfoo 這個程式庫的上游 tarball 原始碼壓縮包的名字從 libfoo-7.0.tar.gz 更新為了 libfoo-8.0.tar.gz,同時帶有一次 SONAME 大版本的跳躍(並因此影響了其它套件)。

程式庫的二進位制套件將必須從 libfoo7 重新命名為 libfoo8 以保持使用 unstable 套件的系統上所有依賴該程式庫的套件在上傳了基於 libfoo-8.0.tar.gz 的新程式庫後仍然能夠正常運行。

[警告]警告

如果這個二進位制程式庫套件沒有得到更名,許多使用 unstable 套件的系統上的各個依賴該程式庫的套件會在新的程式庫包上傳後立刻破損,即便立刻請求進行 binNMU 上傳也無法避免這個問題。由於種種原因,binNMU 不可能在上傳後立刻開始進行,故無法緩解問題。

-dev 套件必須遵循以下命名規則:

[提示]提示

如果包內資料檔案編碼方案有所變化(如,從 latin1 變為 utf-8),該場景應比照 API 變化做類似的考慮與處理。

參見 節 10.9, “程式庫套件”

When you package a new library package version which affects other packages, you must file a transition bug report against the release.debian.org pseudo package using the reportbug command with the ben file and wait for the approval for its upload from the Release Team.

發行團隊提供了變遷追蹤系統。參見 變遷(Transition)

[注意]注意

請確保您按照 節 10.17, “Library package name” 的描述正確地對二進位制套件進行了重命名。

A binNMU” is a binary-only non-maintainer upload performed for library transitions etc. In a binNMU upload, only the Architecture: any packages are rebuilt with a suffixed version number (e.g. version 2.3.4-3 will become 2.3.4-3+b1). The Architecture: all packages are not built.

The dependency defined in the debian/control file among binary packages from the same source package should be safe for the binNMU. This needs attention if there are both Architecture: any and Architecture: all packages involved in it.

  • Architecture: any package: depends on Architecture: any foo package

    • Depends: foo (= ${binary:Version})
  • Architecture: any package: depends on Architecture: all bar package

    • Depends: bar (= ${source:Version})
  • Architecture: all package: depends on Architecture: any baz package

    • Depends: baz (>= ${source:Version}), baz (<< ${source:Version}.0~)

The Debian package is built with the debugging information but packaged into the binary package after stripping the debugging information as required by Chapter 10 - Files” of the Debian Policy Manual.

參見

除錯資訊由 dh_strip 命令的預設行為自動打包並進行移除。所分離得到的除錯套件名具有 -dbgsym 的字尾。

  • debian/rules 檔案不應顯性包括 dh_strip
  • Set the Build-Depends to debhelper-compat (>=13) while removing Build-Depends to debhelper in debian/control.

debconf 套件可以幫助我們在下列兩種情況下配置套件:

  • debian-installer(Debian 安裝程式)預安裝時進行非互動式配置。
  • interactively from the menu interface (dialog, gnome, kde, …​)

    • 套件安裝時:由 dpkg 命令呼叫
    • 對已安裝套件:由 dpkg-reconfigure 命令呼叫

套件安裝時的所有使用者互動都必須由這裡的 debconf 系統進行處理,下列配置檔案對這個過程進行控制。

  • debian/binarypackage.config

    • 這是 debconf config 指令碼,用於對使用者詢問對於配置套件必需的問題。
  • debian/binarypackage.template

    • 這是 debconf templates(模板)檔案,用於對使用者詢問對於配置套件必需的問題。

These debconf files are called by package configuration scripts in the binary Debian package

  • DEBIAN/binarypackage.preinst
  • DEBIAN/binarypackage.prerm
  • DEBIAN/binarypackage.postinst
  • DEBIAN/binarypackage.postrm

See dh_installdebconf(1), debconf(7), debconf-devel(7) and 3.9.1 Prompting in maintainer scripts” in the Debian Policy Manual.



[18] 該文件是在 symbols 檔案被引入之前寫成的。

[19] 第六章 - 開發(-DEV)套件中,存在強烈的使用含有 SONAME 版本號的 -dev 套件名而非僅使用 -dev 作為名稱的偏好,但前 ftp-master 成員(Steve Langasek)對此有不同意見。請注意該文件在 multiarch 系統和 symbols 引入之前寫成,可能有一定程度的過時。

[20] This path is compliant with the FHS. Filesystem Hierarchy Standard: /usr/lib : Libraries for programming and packages states Applications may use a single subdirectory under /usr/lib. If an application uses a subdirectory, all architecture-dependent data exclusively used by the application must be placed within that subdirectory.