Chương 3. Sửa đổi mã nguồn

# Chương 3. Sửa đổi mã nguồn

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.

Xin lưu ý rằng không có nhiều thời gian để đi vào tất cả các chi tiết để khắc phục tất cả thượng nguồn, nhưng đây sẽ là một số bước cơ bản và vài vấn đề mà mọi người thường xuyên gặp phải.

## 3.1. Cài đặt quilt

Chương trình quilt cung cấp phương pháp cơ bản để ghi lại các sửa đổi đối với mã nguồn thượng nguồn cho gói Debian. Rất hữu ích khi có một mặc định hơi tùy chỉnh, vì vậy hãy tạo một alias dquilt cho gói Debian bằng cách thêm các dòng sau vào `~/.bashrc`. Dòng thứ hai là tính năng bash-completion gợi ý của của lệnh quilt vào lệnh dquilt:

    alias dquilt="quilt --quiltrc=${HOME}/.quiltrc-dpkg"
    . /usr/share/bash-completion/completions/quilt
    complete -F _quilt_completion -o filenames dquilt

Sau đó hãy tạo tệp `~/.quiltrc-dpkg` như sau:

    d=. ; while [ ! -d $d/debian -a $(readlink -e $d) != / ]; do d=$d/..; done
    if [ -d $d/debian ] && [ -z $QUILT_PATCHES ]; then
        # if in Debian packaging tree with unset $QUILT_PATCHES
        QUILT_PATCHES="debian/patches"
        QUILT_PATCH_OPTS="--reject-format=unified"
        QUILT_DIFF_ARGS="-p ab --no-timestamps --no-index --color=auto"
        QUILT_REFRESH_ARGS="-p ab --no-timestamps --no-index"
        QUILT_COLORS="diff_hdr=1;32:diff_add=1;34:diff_rem=1;31:diff_hunk=1;33:diff_ctx=35:diff_cctx=33"
        if ! [ -d $d/debian/patches ]; then mkdir $d/debian/patches; fi
    fi

Xem quilt(1) và `/usr/share/doc/quilt/quilt.pdf.gz` để biết cách sử dụng quilt.

## 3.2. Sửa lỗi ở thượng nguồn

Hãy giả sử bạn đã tìm thấy một lỗi trong thượng nguồn `Makefile` như sau, dòng `install: gentoo` nên được sửa lại thành `install: gentoo-target`.

    install: gentoo
            install ./gentoo $(BIN)
            install icons/* $(ICONS)
            install gentoorc-example $(HOME)/.gentoorc

Hãy sửa và ghi lại nó bằng lệnh dquilt với bản vá mới là `fix-gentoo-target.patch`: [22]

    $ mkdir debian/patches
    $ dquilt new fix-gentoo-target.patch
    $ dquilt add Makefile

Bạn thay đổi tệp tin `Makefile` như sau

    install: gentoo-target
            install ./gentoo $(BIN)
            install icons/* $(ICONS)
            install gentoorc-example $(HOME)/.gentoorc

Lệnh dquilt sẽ tạo ra bản vá `debian/patches/fix-gentoo-target.patch` và thêm mô tả của nó như sau DEP-3: Patch Tagging Guidelines:

    $ dquilt refresh
    $ dquilt header -e
    ... mô tả bản vá

## 3.3. Cài đặt các tệp tin đến đích của chúng

Hầu hết các phần mềm của bên thứ ba cài đặt chính nó vào hệ thống phân cấp thư mục `/usr/local`. Với Debian, người quản trị hệ thống nên dành riêng cho việc sử dụng cá nhân, vì vậy các gói không được sử dụng các thư mục như `/usr/local/bin` nhưng nên sử dụng thư mục hệ thống như `/usr/bin`, tuân theo Tiêu chuẩn Phân cấp Hệ thống Tập tin(Filesystem Hierarchy Standard) (FHS).

Thông thường, make(1) được sử dụng để tự động xây dựng chương trình và thực hiện `make install` để cài đặt các chương trình trực tiếp tới đích mong muốn (sau phần `install` là target trong `Makefile`). Để Debian tạo ra các gói trước khi cài đặt, nó sẽ sửa đổi hệ thống xây dựng để cài đặt các chương trình vào cây thư mục giả định dưới một thư mục tạm thay vì một đích thực.

Hai khác biệt giữa cài đặt chương trình bình thường và hệ thống đóng gói Debian có thể được hiểu rõ bởi gói `debhelper`qua lệnh dh_auto_configure và dh_auto_install nếu đáp ứng các điều kiện sau:

- Tệp `Makefile` phải tuân theo các quy ước GNU và hỗ trợ biến `$(DESTDIR)` . [23]

- Mã nguồn phải tuân theo Filesystem Hierarchy Standard (FHS)

Các chương trình sử dụng GNU autoconf tuân theo các quy ước của GNU một cách tự động, do đó chúng rất dễ đóng gói. Trên cơ sở điều này cùng các phương pháp chẩn đoán khác, người ta ước tính rằng `debhelper` sẽ hoạt động với khoảng 90% gói mà không làm thay đổi gì đối hệ thống xây dựng của thượng nguồn. Vì vậy, việc đóng gói không phải là phức tạp như bạn thấy

Nếu bạn cần thực hiện thay đổi tệp `Makefile`, bạn nên cẩn thận hỗ trợ biến `$(DESTDIR)`. Mặc dù nó bị bỏ bởi mặc định, biến `$(DESTDIR)` được thêm vào cho mỗi đường dẫn tập tin dể cài đặt chương trình. Kịch bản đóng gói sẽ đặt `$(DESTDIR)` là thư mục tạm thời.

Đối với một gói nguồn tạo ra một gói nhị phân duy nhất, thư mục tạm thời được sử dụng bởi lệnh dh_auto_install sẽ được cài đặt vào `debian/`package``. [24] Tất cả mọi thứ có trong thư mục tạm thời sẽ được cài đặt trên hệ thống của người dùng khi họ cài đặt gói của bạn; Khác biệt duy nhất là dpkg sẽ cài đặt các tập tin vào đường dẫn liên quan đến thư mục gốc thay vì thư mục làm việc của bạn.

Lưu ý rằng ngay cả khi chương trình của bạn cài đặt trong `debian/`package``, nó vẫn cần phải hoạt động chính xác khi cài đặt từ tệp `.deb` vào thư mục gốc. Vì vâỵ bạn không được tạo hệ thống xây dựng cài đặt vào như đường dẫn tuyệt đối như `/home/me/deb/`package`-`version`/usr/share/`package`` ở các tệp tin trong gói.

Đây là một phần tệp tin `Makefile` của `gentoo`[25]:

    # Where to put executable commands on 'make install'?
    BIN     = /usr/local/bin
    # Where to put icons on 'make install'?
    ICONS   = /usr/local/share/gentoo

Chúng ta thấy rằng các tệp được cài đặt vào `/usr/local`. Như đã giải thích ở trên, cây thư mục đó được dành riêng cho việc sử dụng cục bộ trên Debian, do đó cần thay đổi những đường dẫn đó như sau:

    # Where to put executable commands on 'make install'?
    BIN     = $(DESTDIR)/usr/bin
    # Where to put icons on 'make install'?
    ICONS   = $(DESTDIR)/usr/share/gentoo

Vị trí chính xác cần được sử dụng cho các tệp nhị phân, icons, tài liệu, v.v. được xác định trong Filesystem Hierarchy Standard (FHS). Bạn nên đọc qua nó và các phần có liên quan đến gói của bạn.

Vậy, chúng ta nên cài đặt chương trình vào `/usr/bin` thay vì `/usr/local/bin`, trang hướng dẫn vào `/usr/share/man/man1` thay vì `/usr/local/man/man1`, và vân vân. Chú ý là không có trang hướng dẫn trong `Makefile` của `gentoo`, nhưng vì Debian Policy đòi hỏi mọi chương trình phải có, chúng ta sẽ làm sau và sẽ cài đặt nó trong `/usr/share/man/man1`.

Một số chương trình không sử dụng biến trong `Makefile` để xác định các đường dẫn như vậy. Điều này có nghĩa là bạn có thể phải chỉnh sửa một số mã nguồn C để khắc phục chúng giúp sử dụng đúng vị trí. Nhưng tìm kiếm ở đâu, và chính xác những gì? Bạn có thể tìm ra điều này bằng cách thực hiện:

    $ grep -nr --include='*.[c|h]' -e 'usr/local/lib' .

lệnh grep này sẽ tìm đệ quy trong cây mã nguồn và cho bạn tên tập tin và vị trí dòng chứa cụm từ `usr/local/lib`.

Sửa đổi các tệp và thay thế `usr/local/lib` bằng `usr/lib`. Điều này có thể thực hiện tự động như sau:

    $ sed -i -e 's#usr/local/lib#usr/lib#g' \
            $(find . -type f -name '*.[c|h]')

Nếu bạn muốn xác nhận của mỗi lần thay thế thay, điều này có thể được thực hiện như sau:

    $ vim '+argdo %s#usr/local/lib#usr/lib#gce|update' +q \
            $(find . -type f -name '*.[c|h]')

Tiếp theo, bạn nên tìm mục `install` (tìm kiếm dòng bắt đầu bằng `install:` thường sẽ có) và đổi tên tất cả các tham chiếu tới các thư mục khác. Được xác định ở trên cùng của `Makefile`.

Bản gốc ban đầu, mục `install` của `gentoo` như sau:

    install: gentoo-target
            install ./gentoo $(BIN)
            install icons/* $(ICONS)
            install gentoorc-example $(HOME)/.gentoorc

Hãy sửa lỗi thượng nguồn này và ghi lại nó bằng lệnh dquilt dưới dạng `debian/patches/install.patch`.

    $ dquilt new install.patch
    $ dquilt add Makefile

Trong trình soạn thảo của bạn, thay đổi này cho gói Debian như sau:

    install: gentoo-target
            install -d $(BIN) $(ICONS) $(DESTDIR)/etc
            install ./gentoo $(BIN)
            install -m644 icons/* $(ICONS)
            install -m644 gentoorc-example $(DESTDIR)/etc/gentoorc

Bạn sẽ nhận thấy rằng hiện có một lệnh `install -d` trước các lệnh khác trong quy tắc. Tệp `Makefile` ban đầu không có nó bởi vì thường thư mục `/usr/local/bin` và các thư mục khác đã tồn tại trên hệ thống mà bạn đang chạy `make install`. Tuy nhiên, khi chúng ta sẽ cài đặt vào một cây thư mục cá nhân mới, chúng ta sẽ phải tạo ra một trong những thư mục đó.

Chúng ta cũng có thể thêm vào những thứ khác ở cuối quy tắc, như việc cài đặt các tài liệu bổ sung mà các tác giả thượng nguồn đôi khi bỏ qua:

            install -d $(DESTDIR)/usr/share/doc/gentoo/html
            cp -a docs/* $(DESTDIR)/usr/share/doc/gentoo/html

Kiểm tra cẩn thận, và nếu mọi thứ đều ổn, hãy yêu cầu dquilt tạo ra bản vá vào `debian/patches/install.patch` và thêm mô tả cho nó:

    $ dquilt refresh
    $ dquilt header -e
    ... mô tả bản vá

Bây giờ bạn có một loạt các bản vá.

1. Bản vá thượng nguồn: `debian/patches/fix-gentoo-target.patch`

2. Bản vá việc đóng gói riêng cho Debian: `debian/patches/install.patch`

Bất cứ khi nào bạn thực hiện các thay đổi không phải đặc trưng cho gói Debian như `debian/patches/fix-gentoo-target.patch`, hãy chắc chắn gửi chúng đến người bảo trì thượng nguồn để có thể được áp dụng vào trong phiên bản kế tiếp của chương trình, sẽ là hữu ích cho mọi người khác. Đồng thời nhớ tránh tạo các bản sửa lỗi cụ thể cứng nhắc cho Debian hoặc Linux — hoặc thậm chí là Unix! Hãy làm cho chúng di động. Điều này sẽ làm cho các bản sửa lỗi của bạn dễ dàng hơn để áp dụng.

Nhớ rằng bạn không phải gửi toàn bộ tệp `debian/*` tới thượng nguồn.

## 3.4. Thư viện khác

Có một vấn đề phổ biến khác: các thư viện thường khác nhau từ nền tảng này đến nền tảng khác. Ví dụ, một tệp `Makefile` có thể chứa một tham chiếu đến thư viện không tồn tại trên hệ thống Debian. Trong trường hợp đó, chúng ta cần thay đổi nó thành một thư viện tồn tại trong Debian nhưng phục vụ cùng một mục đích.

Hãy giả sử một dòng trong `Makefile` của chương trình của bạn (hoặc `Makefile.in`) như sau.

    LIBS = -lfoo -lbar

Nếu chương trình không biên dịch được khi thư viện `foo` không tồn tại và nó tương đương với thư viện `foo2` được cung cấp trên hệ thống Debian , bạn có thể sửa vấn đề này với `debian/patches/foo2.patch` bằng cách thay đổi từ `foo` sang `foo2`:[26]

    $ dquilt new foo2.patch
    $ dquilt add Makefile
    $ sed -i -e 's/-lfoo/-lfoo2/g' Makefile
    $ dquilt refresh
    $ dquilt header -e
    ... mô tả bản vá

[22] Thư mục `debian/patches` sẽ tồn tại nếu bạn đã chạy dh_make như đã mô tả trước. Thao tác ví dụ này cũng tạo ra nhưng chỉ trong trường hợp bạn đang cập nhật một gói hiện có.

[23] Xem GNU Coding Standards: 7.2.4 DESTDIR: Support for Staged Installs.

[24] Với một gói mã nguồn tạo ra nhiều gói nhị phân, lệnh dh_auto_install sử dụng thư mục `debian/tmp` như là thư mục tạm thời trong khi lệnh dh_install sẽ tạo ra các kịch bản `debian/`package-1`.install` và `debian/`package-2`.install` sẽ chia nội dung của `debian/tmp` vào thư mục tạm thời là `debian/`package-1`` và `debian/`package-2``, để tạo gói nhị phân ``package-1`_*.deb` và ``package-2`_*.deb`.

[25] Đây chỉ là một ví dụ để xem `Makefile` trông như thế nào. Nếu `Makefile` được tạo bởi lệnh ./configure, cách chính xác để sửa lỗi trên `Makefile` là thực thi ./configure từ lệnh dh_auto_configure với các tùy chọn mặc định bao gồm `--prefix =/usr` .

[26] Nếu có sự thay đổi API từ thư viện `foo` sang thư viện `foo2`, yêu cầu thay đổi mã nguồn để khớp với API mới.

Chương 2. Những bước đầu tiên |  | Chương 4. Các tệp yêu cầu trong thư mục `debian`