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

Содержание

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

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

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

alias dquilt="quilt --quiltrc=${HOME}/.quiltrc-dpkg"
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
    # если в пакетируемом дереве Debian не задана $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.

Предположим, вы нашли ошибку в файле Makefile из архива программы — вместо install: gentoo должно быть 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

Данные настройки предполагают установку в /usr/local. Как указывалось ранее, эта иерархия каталогов зарезервирована для локального использования в Debian, поэтому измените этот путь на:

# Куда помещать исполняемые файлы по команде «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

Всякий раз внося изменения, которые не относятся к пакету Debian, как те, что содержатся в debian/patches/fix-gentoo-target.patch, не забывайте отправлять их сопровождающему программы, чтобы он мог включить эти правки в следующую версию и они стали доступны всем. Перед отправкой ещё раз убедитесь, что ваши исправления не относятся только к Debian или Linux (или даже вообще Unix) — это требуется для переносимости. Такие исправления легче применять.

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

Нередко можно столкнуться с проблемой несовпадения библиотек на различных платформах. Например, файл Makefile может содержать ссылки на библиотеку, которой нет в Debian. В этом случае вы должны изменить ссылку, указав библиотеку, служащую тем же самым целям, но присутствующую в Debian.

Предположим, что в программе есть 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.