Глава 3. Изменение исходного кода

# Глава 3. Изменение исходного кода

The rewrite of this tutorial document with updated contents and more practical examples is available as Guide for Debian Maintainers. Please use this new tutorial as the primary tutorial document.

Заметим, что в данный документ невозможно поместить всю информацию по исправлению исходного кода программы, однако здесь приведены основные шаги и проблемы, с которыми часто встречаются люди.

## 3.1. Настройка quilt

Программа quilt предлагает простой способ записи изменений, произведённых в исходном коде для пакетирования Debian. Для удобства использования слегка изменим настройки по умолчанию, добавив для пакетирования псевдоним dquilt в файле `~/.bashrc`. Вторая строка служит для включения автодополнения к dquilt, такого же как у команды quilt:

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

Затем создадим файл `~/.quiltrc-dpkg` со следующим содержимым:

    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

О том, как использовать quilt, читайте в quilt(1) и `/usr/share/doc/quilt/quilt.pdf.gz`.

## 3.2. Исправление ошибок в исходной программе

Let's assume you find an error in the upstream `Makefile` as follows, where `install: gentoo` should have been `install: gentoo-target`.

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

Внесём исправление и запишем его при помощи команды dquilt в файл `fix-gentoo-target.patch` [22]:

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

Изменим файл `Makefile` следующим образом:

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

Запустите dquilt для генерации и записи заплаты в файл `debian/patches/fix-gentoo-target.patch` и добавьте к ней описание в соответствии с DEP-3: Руководство по маркировке заплат:

    $ dquilt refresh
    $ dquilt header -e
    ... описание заплаты

## 3.3. Установка файлов в их каталоги назначения

Большинство стороннего ПО устанавливает себя в иерархию каталогов `/usr/local`. В Debian это место зарезервировано для использования администратором по своему усмотрению, поэтому пакеты не должны использовать такие каталоги как `/usr/local/bin`, а должны устанавливаться в системные каталоги, такие как `/usr/bin`, согласно стандарту иерархии файловой системы (FHS).

Обычно, для автоматизации сборки программы используется make(1), а по команде `make install` выполняется установка программ в желаемый каталог, назначенный для цели `install` в файле `Makefile`. Для создания двоичных, готовых к установке пакетов Debian, требуется изменить систему сборки таким образом, чтобы она устанавливала программы в образ файловой системы, развёрнутый во временном каталоге, а не в реальное место назначения.

Эти два различия между нормальной установкой программы, с одной стороны, и системой пакетирования Debian с другой, могут быть прозрачно переданы пакетом `debhelper` с помощью команд dh_auto_configure и dh_auto_install, если соблюдаются следующие условия:

- Файл `Makefile` соответствует соглашениям GNU и поддерживает переменную `$(DESTDIR)` [23].

- Исходный код следует FHS.

Программы, использующие пакет GNU autoconf, автоматически следуют соглашениям GNU, и их легко пакетировать. На основе этого и эвристики можно сделать вывод, что пакет `debhelper` будет работать с почти 90% пакетов без внесения серьёзных изменений в их системы сборки. Поэтому процесс пакетирования не так сложен, как кажется.

Если вам необходимо внести изменения в файл `Makefile`, убедитесь, что он поддерживает переменную `$(DESTDIR)`. Значение переменной `$(DESTDIR)` явно в нём не задаётся, но указывается в начале каждого файлового пути, который используется для установки программы. Сценарий пакетирования присвоит `$(DESTDIR)` значение временного каталога.

При создании из исходного кода одиночного пакета временный каталог, используемый командой dh_auto_install, будет установлен в `debian/`пакет`` [24]. Всё, что содержится во временном каталоге, будет помещено в систему пользователя при установке пакета. Различие в том, что dpkg установит файлы в систему относительно корневого каталога, а не вашего рабочего каталога.

Помните: даже если ваша программа устанавливается в `debian/`пакет``, нужно внимательно следить за правильностью её установки из пакета `.deb` в корневой каталог. Поэтому вы не должны разрешать системе сборки записывать неизменяемые строки вроде `/home/моего/deb/`пакет`-`версия`/usr/share/`пакет`` в файлы пакета.

Вот соответствующая часть файла `Makefile`, взятого из пакета `gentoo`[25]:

    # Куда помещать исполняемые файлы по команде «make install»?
    BIN     = /usr/local/bin
    # Куда помещать значки по команде «make install»?
    ICONS   = /usr/local/share/gentoo

We see that the files are set to install under `/usr/local`. As explained above, that directory hierarchy is reserved for local use on Debian, so change those paths as follows:

    # Куда помещать исполняемые файлы по команде «make install»?
    BIN     = $(DESTDIR)/usr/bin

    # Куда помещать значки по команде «make install»?
    ICONS   = $(DESTDIR)/usr/share/gentoo

Где именно должны располагаться исполняемые файлы, значки, документация и т.д. описывает FHS — стандарт иерархии файловой системы. Рекомендуется обратить внимание на разделы, которые касаются вашего пакета.

Итак, исполняемые файлы следует устанавливать в `/usr/bin` вместо `/usr/local/bin`, справочные страницы в `/usr/share/man/man1` вместо `/usr/local/man/man1` и т.д. Обратите внимание, что хотя в `Makefile` из пакета `gentoo` отсутствует упоминание о справочной странице, Debian Policy требует её наличия для каждой программы, поэтому позднее мы создадим такую страницу и установим её в `/usr/share/man/man1`.

Некоторые программы не используют переменные в `Makefile` для подобного указания путей. Это означает, что, возможно, вам придётся редактировать исходные файлы, написанные на языке C, для указания правильного расположения. Но где и как искать эти пути? Для этого вы можете воспользоваться следующей командой:

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

Команда grep рекурсивно обходит всё дерево исходного кода и при обнаружении совпадений сообщает вам имя соответствующего файла и номер строки.

Отредактируйте указанные строки в этих файлах, заменив `usr/local/lib` на `usr/lib`. Это можно сделать автоматически с помощью команды:

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

Если вы хотите подтверждать каждую замену, запустите следующую команду:

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

После этого вам нужно найти цель `install` (обычно достаточно найти строку, начинающуюся с `install:`) и заменить все ссылки на каталоги, которые отличаются от указанных в начале файла `Makefile`.

Первоначально, цель `install` в `gentoo` была такой:

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

Давайте исправим ошибку с путями в исходной программе и запишем её при помощи команды dquilt в файл `debian/patches/install.patch`.

    $ dquilt new install.patch
    $ dquilt add Makefile

Воспользуемся редактором для внесения в пакет Debian следующих изменений:

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

Разумеется вы заметили, что в начале цели появилась команда `install -d`. В исходном `Makefile` её не было, так как обычно `/usr/local/bin` и другие каталоги уже существуют в системе на момент запуска `make install`. Однако, так как мы будем проводить установку в создаваемый каждый раз свой каталог, нам следует создать в нём все необходимые каталоги.

В конец правила установки мы можем добавить что-нибудь ещё, например, установку дополнительной документации, которую не включили авторы программы:

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

Убедившись, что всё сделано правильно, c помощью dquilt сгенерируем заплату `debian/patches/install.patch` и добавим её описание:

    $ dquilt refresh
    $ dquilt header -e
    ... описание заплаты

Теперь у вас есть несколько заплат:

1. Заплата для исправления ошибки в программе: `debian/patches/fix-gentoo-target.patch`

2. Изменения, необходимые для создания пакета Debian: `debian/patches/install.patch`

Whenever you make changes that are not specific to the Debian package such as `debian/patches/fix-gentoo-target.patch`, be sure to send them to the upstream maintainer so they can be included in the next version of the program and be useful to everyone else. Also remember to avoid making your fixes specific to Debian or Linux — or even Unix! Make them portable. This will make your fixes much easier to apply.

Не отправляйте разработчикам программы файлы `debian/*`.

## 3.4. Несовпадение библиотек

There is one other common problem: libraries are often different from platform to platform. For example, a `Makefile` can contain a reference to a library that doesn't exist on the Debian system. In that case, we need to change it to a library that does exist in Debian, and serves the same purpose.

Предположим, что в программе есть `Makefile` (или `Makefile.in`) со строкой следующего вида:

    LIBS = -lfoo -lbar

Если ваша программа не компилируется из-за отсутствия библиотеки `foo` и в Debian для неё есть замена в виде `foo2`, то вы можете исправить проблему со сборкой с помощью `debian/patches/foo2.patch`, который заменяет `foo` на `foo2`:[26]

    $ dquilt new foo2.patch
    $ dquilt add Makefile
    $ sed -i -e 's/-lfoo/-lfoo2/g' Makefile
    $ dquilt refresh
    $ dquilt header -e
    ... описание заплаты

[22] Каталог `debian/patches` уже должен существовать, если вы запускали dh_make, как это описывалось ранее. В этом примере каталог создаётся вручную, на случай если обновляется существующий пакет.

[23] Смотрите Стандарты программирования GNU: 7.2.4 DESTDIR: Поддержка поэтапной установки.

[24] При создании из исходного кода нескольких двоичных пакетов команда dh_auto_install использует `debian/tmp` в качестве временного каталога, а команда dh_install с помощью файлов `debian/`пакет-1`.install` и `debian/`пакет-2`.install` разнесёт содержимое `debian/tmp` по временным каталогам `debian/`пакет-1`` и `debian/`пакет-2`` для создания двоичных пакетов ``пакет-1`_*.deb` и ``пакет-2`_*.deb`.

[25] Это просто пример, который показывает как должен выглядеть `Makefile`. Если `Makefile` создан командой ./configure, то исправлять файл `Makefile` предпочтительно вызовом ./configure из dh_auto_configure с параметрами по умолчанию и добавленным параметром `--prefix=/usr`.

[26] Если изменяется программный интерфейс (API) (то есть, вместо библиотеки `foo` начинают использовать библиотеку `foo2`), то требуется изменить исходный код так, чтобы он использовал новый API.

Глава 2. Первые шаги |  | Глава 4. Обязательные файлы в каталоге `debian`