Phụ lục A. Đóng gói nâng cao

# Phụ lục A. Đóng gói nâng cao

Việc viết lại tài liệu này với các nội dung cập nhật và nhiều các ví dụ thực tế hơn đã có ở Guide for Debian Maintainers. Vui lòng sử dụng tài liệu mới này như là tài liệu hướng dẫn chính.

Sau đây là một vài gợi ý và chỉ dẫn cho các đề tài đóng gói nâng cáo mà bạn rất có thể phải đối mặt. Bạn rất được khuyến khích đọc tất cả những tài liệu liên quan được đề nghị ở đây.

Bạn có thể cần phải thay đổi các tập tin khuôn mẫu đóng gói tạo ra bởi lệnh dh_make để biết được các đề tài được nói tới trong chương này. Lệnh debmake mới hơn có thể sẽ nói về các đề tài này tốt hơn.

## A.1. Các thư viện được chia sẻ

Trước khi đóng gói các thư viện được chia sẻ, bạn nên đọc những tài liệu liên quan sau một cách chi tiết:

- Hướng dẫn về Chính sách Debian, 8 "Các Thư viện Chia sẻ"

- Hướng dẫn về Chính sách Debian, 9.1.1 "Cấu trúc Hệ thống tập tin"

- Hướng dẫn về Chính sách Debian, 10.2 "Các Thư viện"

Sau đây là một số gợi ý được đơn giản hóa quá mức để giúp bạn bắt đầu:

- Các thư viện chia sẻ là các tập tin đối tượng ELF chứa mã biên dịch.

- Các thư viện chia sẻ được phân phối bởi các tập tin `*.so`. (Không phải các tập tin `*.a` hay các tập tin `*.la`)

- Các thư viện chia sẻ được sử dụng phần lớn để chia sẻ những mã thông dụng giữa nhiều tập tin thực thi với cơ chế ld.

- Các thư viện chia sẻ thỉnh thoảng được sử dụng để cung cấp nhiều phần mở rộng có thể cắm vào một tập tin thực thi với cơ chế dlopen.

- Các thư viện chia sẻ xuất các ký hiệu đại diện cho các đối tượng được biên dịch như là các tham biến, các hàm, và các class; và cho phép truy cập tới chúng từ các tập tin thực thi được kết nối tới chúng.

- SONAME của một thư viện chia sẻ `lib`foo`.so`.`1`: `objdump -p lib`foo`.so.`1` | grep SONAME` [87]

- SONAME của một thư viện chia sẻ thường khớp với tên tập tin thư viện (nhưng không phải luôn luôn như vậy).

- SONAME của các thư viện chia sẻ được kết nối tới ``/usr/bin/foo``: `objdump -p `/usr/bin/foo` | grep NEEDED` [88]

- `lib`foo``1``: gói phần mềm thư viện cho thư viện chia sẻ `lib`foo`.so.`1`` với phiên bản SONAME ABI `1`.[89]

- Các kịch bản bảo trì gói phần mềm của gói phần mềm thư viện phải gọi lệnh ldconfig dưới các tình huống cụ thể để tạo các kết nối tượng trưng cho SONAME.[90]

- `lib`foo``1`-dbg`: gói phần mềm ký hiệu dò lỗ chứa các ký hiệu dò lỗi cho gói phần mềm thư viện chia sẻ `lib`foo``1``.

- `lib`foo`-dev`: gói phần mềm phát triển chứa những tập tin tiêu đề v.v. cho thư viện chia sẻ `lib`foo`.so.`1``.[91]

- Các gói Debian không nên chứa các tập tin lưu trữ `*.la` nói chung.[92]

- Gói phần mềm Debian nói chung không nên sử dụng RPATH.[93]

- Mặc dù nó có thể đã lạc hậu và chỉ tồn tại như là tài liêu tham khảo thứ cấp, Hướng dẫn Đóng gói thư viện Debian có thể vẫn hữu dụng.

## A.2. Quản lý `debian/`package`.symbols`

Khi bạn đóng gói một thư viện chia sẻ, bạn nên tạo một tập tin `debian/`package`.symbols` để quản lý phiên bản thấp nhất liên quan tới từng ký hiệu cho các thay đổi ABI tương thích ngược dưới cùng một SONAME của thư viện cho cùng một tên gói phần mềm thư viện.[94] Bạn nên đọc những tài liệu liên quan chính thống sau đây một cách chi tiết:

- Hướng dẫn Chính sách Debian, 8.6.3 "Hệ thống ký hiệu"[95]

- dh_makeshlibs(1)

- dpkg-gensymbols(1)

- dpkg-shlibdeps(1)

- deb-symbols(5)

Sau đây là một ví dụ sơ khảo để tạo một gói phần mềm `libfoo1` tương ứng với phiên bản thượng nguồn `1.3` với tập tin `debian/libfoo1.symbols` phù hợp:

- Chuẩn bị một sườn cho cây mã nguồn Debian hóa sử dụng tập tin thượng nguồn `libfoo-1.3.tar.gz`.

  - Nếu đây là lần đóng gói đầu tiên của gói phần mềm `libfoo1`, tạo một tập tin `debian/libfoo1.symbols` rỗng.

  - Nếu phiên bản thượng nguồn trước đó `1.2` được đóng gói thành gói phần mềm `libfoo1` với một tập tin `debian/libfoo1.symbols` phù hợp trong gói phần mềm nguồn của nó, hãy sử dụng lại tập tin đó.

  - Nếu bản thượng nguồn trước đó `1.2` không được đóng gói với tập tin `debian/libfoo1.symbols`, tạo một tập tin như là tập tin `symbols` từ tất cả các gói phần mềm nhị phân có sẵn của một tên gói phần mềm thư viện chứa cùng SONAME của một thư viện, ví dụ, các phiên bản `1.1-1` và `1.2-1`. [96]

        $ dpkg-deb -x libfoo1_1.1-1.deb libfoo1_1.1-1
        $ dpkg-deb -x libfoo1_1.2-1.deb libfoo1_1.2-1
        $ : > symbols
        $ dpkg-gensymbols -v1.1 -plibfoo1 -Plibfoo1_1.1-1 -Osymbols
        $ dpkg-gensymbols -v1.2 -plibfoo1 -Plibfoo1_1.2-1 -Osymbols

- Tạo các bản biên dịch thử của cây mã nguồn với các công cụ như là debuild và pdebuild. (Nếu điều này thất bại do thiếu ký hiệu v.v., đã có một số thay đổi ABI không tương thích ngược buộc bạn phải tăng tên gói phần mềm thư viện chia sẻ lên một tên như là `libfoo1a` và bạn nên bắt đầu lại từ đầu.)

      $ cd libfoo-1.3
      $ debuild
      ...
      dpkg-gensymbols: warning: some new symbols appeared in the symbols file: ...
       see diff output below
      --- debian/libfoo1.symbols (libfoo1_1.3-1_amd64)
      +++ dpkg-gensymbolsFE5gzx        2012-11-11 02:24:53.609667389 +0900
      @@ -127,6 +127,7 @@
        foo_get_name@Base 1.1
        foo_get_longname@Base 1.2
        foo_get_type@Base 1.1
      + foo_get_longtype@Base 1.3-1
        foo_get_symbol@Base 1.1
        foo_get_rank@Base 1.1
        foo_new@Base 1.1
      ...

- Nếu bạn thấy sự khác biệt in ra bởi lệnh dpkg-gensymbols như trên, giải nén tập tin `symbols` phù hợp cập nhật mới nhất từ gói phần mềm nhị phân được tạo ra của thư viện chia sẻ. [97]

      $ cd ..
      $ dpkg-deb -R  libfoo1_1.3_amd64.deb libfoo1-tmp
      $ sed -e 's/1\.3-1/1\.3/' libfoo1-tmp/DEBIAN/symbols \
              >libfoo-1.3/debian/libfoo1.symbols

- Biên dịch các gói phần mềm phát hành với các công cụ như debuild và pdebuild.

      $ cd libfoo-1.3
      $ debuild -- clean
      $ debuild
      ...

Bên cạnh các ví dụ ở trên, chúng ta cần phải kiểm tra tương thích ABI hơn nữa và tăng các phiên bản cho một vài ký hiệu bằng tay nếu cần. [98]

Mặc dù đây chỉ là một tài liệu tham khảo thứ cấp, Debian wiki UsingSymbolsFiles và những trang điện tử kết nối tới nó có thể rất hữu dụng.

## A.3. Multiarch

Tính năng multiarch được giới thiệu ở Debian wheezy tích hợp hỗ trợ cho cài đặt xuyên nền tảng của các gói phần mềm nhị phân (đặc biệt `i386`<->`amd64`, nhưng cũng một vài kết hợp khác) trong `dpkg` và `apt`. Bạn nên đọc các tài liệu tham khảo sau một cách chi tiết:

- Ubuntu wiki MultiarchSpec (thượng nguồn)

- Debian wiki Multiarch/Implementation (tình huống Debian)

Nó sử dụng bộ ba như là `i386-linux-gnu` và `x86_64-linux-gnu` cho đường dẫn cài đặt của các thư viện chia sẻ. Đường dẫn bộ ba thực sự được đặt giá trị linh động theo tham biến `$(DEB_HOST_MULTIARCH)` dùng lệnh dpkg-architecture(1) cho từng lần biên dịch gói phần mềm nhị phân. Ví dụ, đường dẫn để cài đặt các thư viện multiarch được thay đổi như sau:[99]

Đường dẫn cũ | Đường dẫn i386 multiarch | Đường dẫn amd64 multiarch
--- | --- | ---
`/lib/` | `/lib/i386-linux-gnu/` | `/lib/x86_64-linux-gnu/`
`/usr/lib/` | `/usr/lib/i386-linux-gnu/` | `/usr/lib/x86_64-linux-gnu/`

Sau đây là một vài ví dụ về tình huống băm gói phần mềm multiarch tiêu biểu cho các gói:

- một gói phần mềm nguồn cho `lib`foo`-1.tar.gz`

- một gói phần mềm nguồn công cụ ``bar`-1.tar.gz` viết bằng một ngôn ngữ biên dịch.

- một gói phần mềm nguồn công cụ ``baz`-1.tar.gz` viết bằng một ngôn ngữ thông dịch

Package | Architecture: | Multi-Arch: | Nội dung gói phần mềm
--- | --- | --- | ---
`lib`foo``1`` | bất kỳ | không đổi | thư viện được chia sẻ, có thể cài cùng lúc
`lib`foo``1`-dbg` | bất kỳ | không đổi | các ký hiệu dò lỗi của thư viện chia sẻ, có thể cài cùng lúc
`lib`foo`-dev` | bất kỳ | không đổi | các tập tin tiêu đề của thư viện chia sẻ v.v., có thể cài cùng lúc
`lib`foo`-tools` | bất kỳ | Xa lạ | Các chương trình hỗ trợ khi chạy, không thể cài đặt cùng lúc
`lib`foo`-doc` | tất cả | Xa lạ | những tập tin tài liệu hướng dẫn của thư viện chia sẻ
``bar`` | bất kỳ | Xa lạ | các tập tin chương trình đã biên dịch, không thể cài đặt cùng lúc
``bar`-doc` | tất cả | Xa lạ | những tập tin tài liệu hướng dẫn cho chương trình
``baz`` | tất cả | Xa lạ | các tập tin chương trình được thông dịch

Xin chú ý rằng gói phần mềm phát triển nên chứa một kết nối tượng trưng cho thư viện chia sẻ tương ứng không có số phiên bản. Ví dụ: `/usr/lib/x86_64-linux-gnu/libfoo.so` -> `libfoo.so.1`

## A.4. Biên dịch một gói phần mềm chia sẻ

Bạn có thể biên dịch một gói phần mềm thư viện Debian cho phép hỗ trợ multiarch dh(1) như sau:

- Cập nhật `debian/control`.

  - Thêm `Build-Depends: debhelper (>=10)` cho phần gói phần mềm nguồn.

  - Thêm `Pre-Depends: ${misc:Pre-Depends}` cho mỗi gói phần mềm nhị phân thư viện chia sẻ.

  - Thêm `Multi-Arch:` cho mỗi phần tương ứng với mỗi gói phần mềm nhị phân.

- Đặt giá trị 10 cho `debian/compat`.

- Điều chỉnh đường dẫn từ `/usr/lib/` bình thường sang multiarch `/usr/lib/$(DEB_HOST_MULTIARCH)/` cho tất cả kịch bản đóng gói.

  - Gọi `DEB_HOST_MULTIARCH ?= $(shell dpkg-architecture -qDEB_HOST_MULTIARCH)` trong `debian/rules` để đặt giá trị cho tham biến `DEB_HOST_MULTIARCH` trước tiên.

  - Thay thế `/usr/lib/` với `/usr/lib/$(DEB_HOST_MULTIARCH)/` trong `debian/rules`.

  - Nếu `./configure` được sử dụng trong một phần của mục tiêu `override_dh_auto_configure` trong `debian/rules`, chắc chắn rằng bạn thay thế nó với `dh_auto_configure --` . [100]

  - Thay thế hết tất cả các sự xuất hiện của `/usr/lib/` với `/usr/lib/*/` trong các tập tin `debian/`foo`.install`.

  - Tạo ra các tập tin như `debian/`foo`.links` từ `debian/`foo`.links.in` một cách tự động bắng thêm một kịch bản vào mục tiêu `override_dh_auto_configure` trong `debian/rules`.

        override_dh_auto_configure:
                dh_auto_configure
                sed 's/@DEB_HOST_MULTIARCH@/$(DEB_HOST_MULTIARCH)/g' \
                        debian/foo.links.in > debian/foo.links

Hãy chắc chắn rằng gói phần mềm thư viện chia sẻ chỉ chứa duy nhất các tập tin được trông đợi, và gói phần mềm -dev của bạn vẫn hoạt động tốt.

Tất cả các tập tin được cài đặt cùng lúc với gói phần mềm multiarch vào cùng một đường dẫn nên có cùng một nội dung chính xác như nhau. Bạn phải cẩn thận với những sự khác biệt tạo ra bởi thứ tự byte dữ liệu và thuật toán nén.

## A.5. Gói phần mềm Debian native

Nếu một gói phần mề được bảo trì chỉ cho Debian hoặc có thể chỉ cho việc dùng nội bộ, mã nguồn của nó có thể chứa tất các tập tin `debian/*` bên trong nó. Có 2 cách để đóng gói nó.

Bạn có thể tạo một tập tin lưu trữ thượng nguồn bằng việc loại trừ tất cả các tập tin `debian/*` và đóng gói nó như là một gói phần mềm nhị phân Debian không native như ở Phần 2.1, “Luồng làm việc tạo ra gói Debian”. Đây là cách thông thường mọi người khuyến khích sử dụng.

Một cách khác là cách làm của một gói phần mềm Debian native.

- Tạo một gói phần mềm nguồn Debian native dưới định dạng `3.0 (native)` bằng việc sử dụng một tập tin nén tar đơn độc chứa tất cả các tập tin bên trong.

  - ``package`_`version`.tar.gz`
  - ``package`_`version`.dsc`

- Biên dịch các gói phần mềm nhị phân Debian từ gói phần mềm nguồn Debian native.

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

Ví dụ, nếu bạn có các tập tin nguồn trong thư mục `~/mypackage-1.0` mà không có các tập tin `debian/*`, bạn có thể tạo một gói phần mềm Debian native cho nó bằng việc chạy lệnh dh_make như sau:

    $ cd ~/mypackage-1.0
    $ dh_make --native

Sau đó thư mục `debian` và nội dụng của nó được tạo như là ở Phần 2.8, “Khởi tạo gói Debian mới”. Hành động này không tạo một tập tin lưu trữ vì đây là một gói phần mềm Debian native. Nhưng đó là điểm khác biệt duy nhất. Phần còn lại của quá trình đóng gói thực tế là không khác gì.

Sau khi chạy lệnh dpkg-buildpackage, bạn sẽ thấy các tập tin sau trong thư mục cha:

- `mypackage_1.0.tar.gz`

  Đây là tập tin mã nguồn tạo ra từ thư mục `mypackage-1.0` bởi lệnh dpkg-source command. (Phần hậu tố của nó không phải là `orig.tar.gz`.)

- `mypackage_1.0.dsc`

  Đây là bản tóm tắt của những nội dung của mã nguồn như ở trong gói phần mềm Debian không native. (There có mã tu chỉnh Debian.)

- `mypackage_1.0_i386.deb`

  Đây là gói phần mềm nhị phân hoàn chỉnh của bạn như là gói phần mềm Debian không native. (Không có mã tu chỉnh Debian.)

- `mypackage_1.0_i386.changes`

  Tập tin này mô tả những thay đổi được tạo ra trong phiên bản gói phần mềm hiện tại như ở trong gói phần mềm Debian không native. (Không có bản tu chỉnh Debian.)

[87] Ngoài ra: `readelf -d lib`foo`.so.`1` | grep SONAME`

[88] Ngoài ra: `readelf -d lib`foo`.so.`1` | grep NEEDED`

[89] Xem Hướng dẫn về Chính sách Debian, 8.1 "Các Thư viện chia sẻ khi chạy".

[90] Xem Hướng dẫn về Chính sách Debian, 8.1.1 "ldconfig".

[91] Xem Hướng dẫn Chính sách Debian, 10.2 "Các Thư viện tĩnh" và Hướng dẫn về Chính sách Debian, 8.4 "Các Tập tin phát triển"

[92] Xem Debian wiki ReleaseGoals/LAFileRemoval.

[93] Xem Debian wiki RpathIssue.

[94] Các thay đổi ABI không tương thích ngược thông thường cần bạn phải cập nhật SONAME của thư viện và tên gói phần mềm thư viện chia sẻ sang những tên mới.

[95] Với các thư viện C++ và các tình huống khác mà theo dõi từng ký hiệu là vô cùng khó khăn, thay vì như trên hãy làm theo Hướng dẫn Chính sách về Debian, 8.6.4 "Hệ thống shlibs",

[96] Tất cả các phiên bản trước đó của các gói phần mềm Debian có sẵn tại http://snapshot.debian.org/. Phiên bản tu chỉnh Debian được cắt bỏ khỏi phiên bản để giúp việc backport gói phần mềm (tạo gói phần mềm chứa các cập nhật mới cho các bản phân phối Debian cũ) dễ hơn: `1.1` << `1.1-1~bpo70+1` << `1.1-1` và `1.2` << `1.2-1~bpo70+1` << `1.2-1`

[97] Phiên bản tu chỉnh Debian được cắt bỏ khỏi phiên bản để giúp việc backport gói phần mềm (tạo gói phần mềm chứa các cập nhật mới cho các bản phân phối Debian cũ) dễ hơn: `1.3` << `1.3-1~bpo70+1` << `1.3-1`

[98] Xem Hướng dẫn về Chính sách Debian, 8.6.2 "Các Thay đổi ABI của Thư viện chia sẻ"

[99] Các đường dẫn thư viện chuyên dụng cũ như `/lib32/` và `/lib64/` không được sử dụng nữa.

[100] Ngoài ra, bạn có thể thêm các đối số `--libdir=\$${prefix}/lib/$(DEB_HOST_MULTIARCH)` và `--libexecdir=\$${prefix}/lib/$(DEB_HOST_MULTIARCH)` cho `./configure`. Xin hãy chú ý rằng tham số `--libexecdir` thông báo đường dẫn ngầm định để cài đặt các chương trình thực thi được chạy bởi các chương trình khác thay vì bởi người dùng. Giá trị ngầm định Autotools của nó là `/usr/libexec/` nhưng ngầm định của Debian là `/usr/lib/`.

Chương 9. Tải gói phần mềm lên |  |