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

Содержание

3.1. Настройка quilt
3.2. Исправление ошибок в исходной программе
3.3. Установка файлов в их каталоги назначения
3.4. Несовпадение библиотек

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.

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

Программа 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.

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
... описание заплаты

Большинство стороннего ПО устанавливает себя в иерархию каталогов /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/*.

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, как это описывалось ранее. В этом примере каталог создаётся вручную, на случай если обновляется существующий пакет.

[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.