Pull to refresh

Стать мэинтейнером. Часть третья

Configuring Linux *
И был день третий, и задумался хабрапользователь-убунтоид: а как мне запаковать свой любимый пакет, чтобы был он красивый и правильный и чтобы гордость от его кошерности распирала ого-го как. Именно этим мы с вами сегодня и займёмся.
(Части 1, 2 и 4)

По инициативе darkk мы будем собирать пакет redsocks, что в переводе на русский означает «Красные носки darkk'а».
Первым делом идёт по упомянутой ссылке и скачиваем архив с исходниками. Не знаю, как у вас, а у меня он называется «darkk-redsocks-77a490422b701875a9fda2bd7d58e62cb7481f64.tar.gz». Сами понимаете, архив с таким названием — это нехорошо. Поэтому мы первым делом его распаковываем и стираем:
$ tar xvf darkk-redsocks-77a490422b701875a9fda2bd7d58e62cb7481f64.tar.gz
$ rm darkk-redsocks-77a490422b701875a9fda2bd7d58e62cb7481f64.tar.gz

Теперь мы имеем каталог с названием «darkk-redsocks-77a490422b701875a9fda2bd7d58e62cb7481f64». Тоже никуда не годится. К счастью, для крайних случаев, например, вот таких, когда никаких нормальных версий у программы нет вообще, Debian позволяет сменить нумерацию. Этим мы сейчас и займёмся:
$ mv darkk-redsocks-77a490422b701875a9fda2bd7d58e62cb7481f64 darkk-redsocks-2009013101
$ tar czf darkk-redsocks_2009013101.orig.tar.gz darkk-redsocks-2009013101

Первым действием мы переименовываем каталог: теперь версия у нас будет нумероваться по дате плюс номер версии за текущую дату — в этот раз версия будет 01. Вторым создаём «кошерный» архив исходников. Заметьте, кстати, что каталог по правилам должен именоваться как «name-version», а архив — как «name_version.orig.tar.gz». В первом случае перед версией должен стоять дефис, во втором — подчеркивание.
Теперь, как ни странно, если вы знакомы с программой настолько же, насколько и я (то есть видите ее первый раз в жизни), то устанавливаем пакет libevent-dev, который указан в зависимостях программы, и безо всяких изысков пытаемся собрать нашу программу:
$ sudo apt-get install libevent-dev
$ cd darkk-redsocks-2009013101
$ make

Лично у меня эта процедура упала с ошибкой:
cc -std=gnu99 -Wall -g -O0 -c base.c -o base.o
In file included from /usr/include/linux/netfilter_ipv4.h:8,
from base.c:29:
/usr/include/linux/netfilter.h:44: error: field ‘in’ has incomplete type
/usr/include/linux/netfilter.h:45: error: field ‘in6’ has incomplete type
make: *** [base.o] Ошибка 1

И здесь вступает в силу одна из первых заповедей сопровождающего пакет: либо ты очень тесно вступает в контакт с автором апстрима, либо ты становишься крупным специалистом по поиску в интернете. Я из гордости в этот раз предпочёл второй вариант и путём тщательного поиска обнаружил, что баг старый. проявляется уже с полгода и фиксить его почему-то не спешат. Но локальный фикс в пакете сделать можно и мы его сейчас сделаем (маленькое замечание: я опять-таки это не оформляю отдельным патчем, а правлю прямо в коде, потому что такие суровые ошибки культурный человек обязан отослать автору апстрима и пинать его ногами, пока патч не будет в апстрим включен. Если не будет — нафиг таких авторов программ. Так вот, а мы тем временем в файле base.c перед строчкой
# include <linux/netfilter_ipv4.h>
вставляем
# include <netinet/in.h>

Собираем еще раз. Снова ошибка:
cc parser.o main.o redsocks.o log.o http-connect.o socks4.o socks5.o http-relay.o base.o -levent -o redsocks
main.o: In function `terminate':
/home/user/build/darkk-redsocks-2009013101/main.c:44: undefined reference to `event_loopbreak'

Снова лезем в поиск, ничего не обнаруживаем (по крайней мере я), но чудовищным телепатическим усилием понимаем, что имеющийся у нас в репозитории libevent еще не умеет метод event_loopbreak. Окей, говорим мы, что же нам делать? Новая версия в дебиане есть только в репозитории experimental. Лично я его подключать не рискнул. Поэтому мы выполняем следующие действия:
$ cd ..
$ sudo apt-get --purge remove libevent1 libevent-dev
$ dget http://ftp.de.debian.org/debian/pool/main/libe/libevent/libevent_1.4.8~stable-1.dsc
$ cd libevent-1.4.8~stable/
$ debuild
$ cd ..
$ sudo dpkg -i ./libevent*.deb

Поясняю. Поскольку мы не хотим подключать себе репозиторий, в котором море страшно нестабильного софта, мы удаляем имеющийся у нас libevent и собираем исходный пакет новой версии, который мы скачали при помощи команды dget. Теперь, когда мы успешно установили собранный пакет, попробуем собрать наши красные носки еще раз:
$ cd darkk-redsocks-2009013101/
$ make

В этот раз у меня всё собралось успешно. Замечательно. Теперь окидываем взором наш каталог, пробуем понять, какие файлы должны быть собраны в конечный бинарный пакет, который поставит себе на компьютер пользователь. Лично я выделил вот такой набор:
doc/* — документация
README — то же самое
redsocks.conf.example — файл примера
redsocks — сам исполняемый файл

Отлично, теперь давайте опробуем несколько вариантов.

Соберем из готовых бинарников говнопакет

Да, другими словами назвать это сложно, поэтому я вынужден это назвать именно так.
Внимание, данный вариант сборки представлен исключительно для ознакомления и те, кто им пользуется, должны быть семикратно казнены в соответствии с законами страны Оз!
Итак, создаем внутри нашего каталога с собранной программой, еще один каталог «darkk-redsocks-2009013101». Копируем в него файлы так, чтобы получилась следующая иерархия:
darkk-redsocks-2009013101/
|-usr/
.|-bin/
.||-redsocks
.|-share/
..|-doc/
...|-redsocks/
....|-COPYING
....|-README
....|-rfc1929-socks5-auth.txt
....|-rfc2817-http-connect.txt
....|-socks4a.protocol.txt
....|-rfc1928-socks5.txt
....|-rfc1961-socks5-gssapi.txt
....|-rfc3089-socks-ipv6.txt
....|-socks4.protocol.txt
....|-examples/
.....|-redsocks.conf.example

Создаем каталог darkk-redsocks-2009013101/DEBIAN и кладём в него файл control с следующим содержимым:
Package: darkk-redsocks
Version: 2009013101
Architecture: amd64
Maintainer: Ivan Ivanov <ivan@ivanov.iv>
Description: transparent redirector of any TCP connection to proxy
 Mega-package which redirects any TCP connections to somewhat
 damn proxy.

Поскольку нам еще придется работать с файлами control, сразу дам немножко объяснений. Данный файл хранит всё описание пакета — для какой архитектуры он собран, кто его сопровождающий и т. п. В принципе там всё понятно, интерес представляет только пункт Description. Он устроен хитрым образом: в первой строчке, сразу после слова «Description: » записывается краткое описание. Записывать его по правилам надо так, чтобы его можно было подставить в строчку "Packagename is a description". То есть записывается с маленькой буквы, без подлежащего и слова «is» (с возможным артиклем), не содержать на конце какой-либо знак препинания. При этом в кратком описании не должно упоминаться название пакета, и оно должно умещаться в одно предложение и быть не длиннее 60 символов. Начиная со следующей строки идёт полное описание пакета. Каждая строчка в описании опять же должна быть не длиннее 80 символов (это, кстати, общее требование, в том числе и ко всевозможным скриптам) и начинаться с пробела. Если вы хотите вставить в описание пустую строку — поставьте на ней пробел и символ точки. Ну и по доброй дебиановской традиции файл должен заканчиваться пустой строкой.
Ладно, с файлом control покончили. После того, как мы его сохранили, собираем наш пакет командой
$ dpkg -b darkk-redsocks-2009013101

В данном случае, darkk-redsocks-2009013101 — это имя нашего каталога, в который мы запихали файлы для пакета, и по совместительству, оно же станет именем полученного deb-пакета. Насладились зрелищем? Теперь срочно набираем
$ rm -rf darkk-redsocks-2009013101 darkk-redsocks-2009013101.deb
, пока меня окончательно не стошнило от такого метода сборки. И переходим к следующему способу.

Собираем пакет, как культурные люди

И вот, мы опять находимся в ситуации, когда у нас есть собранные бинарники и больше ничего. Давайте исправлять эту ситуацию. Набираем:
$ make distclean

Мы радостно очистили каталог и от бинарника, и от объектных файлов — от всего, что сгенерировалось при сборке. Теперь набираем
$ dh_make
и сообщаем о своём страстном желании создать пакет, который генерирует single binary, то есть, единственный бинарник. Утилита dh_make относится к набору утилит debhelper, которые страшно облегчают жизнь сопровождающим пакеты. Она сгенерировала нам каталог debian, в котором лежат файлы, используемые для сборки пакета. Давайте теперь зайдём в этот каталог и удалим всё, кроме следующих файлов:
changelog
compat
control
copyright
docs
rules

По-хорошему, нам не помешал бы еще файл watch, но поскольку у нас нет нормальных, где-либо выкладываемых релизов, за которыми можно следить, а только git-репозиторий, нам он не понадобится. Теперь откроем файл control, сотрём из него всё и напишем новое, красивое содержимое:
Source: darkk-redsocks
Section: net
Priority: optional
Homepage: http://darkk.net.ru/redsocks
Maintainer: Vsevolod Velichko <torkvemada@nigma.ru>
Build-Depends: debhelper(>=7), libevent-dev(>=1.4.2)
Standards-Version: 3.8.0
Vcs-Git: git://github.com/darkk/redsocks.git
Vcs-Browser: http://github.com/darkk/redsocks/tree/master

Package: darkk-redsocks
Architecture: any
Depends: ${shlibs:Depends}, ${misc:Depends}
Description: transparent redirector of any TCP connection to proxy
 Mega-package which redirects any TCP connections to somewhat
 damn proxy.

Здесь в принципе всё понятно, за исключением пары моментов. Сначала идёт описание пакета исходников, затем, через пустую строку — бинарного пакета. «Architecture: any» означает в данном случае, что в скомпилированный бинарный пакет можно подставить любую архитектуру — под какую соберем, та и подставится. Если бы мы собирали, например, dev-пакет, который один для всех архитектур, мы бы написали туда: «all». Иногда бывает надо, чтобы один src-пакет собирал несколько бинарных пакетов, например, так собирается неоднократно упоминаемый мною qutIM — его исходный код предоставляет не только саму программу, которая собирается в пакет qutim, но и заголовочные файлы для потенциальных плагинов — их мы должны поместить в пакет qutim-dev. В таких случаях мы записываем в файле control описания нескольких собираемых бинарных пакетов подряд, разделяя их пустыми строками. Теперь — секция Build-Depends. Во-первых, в ней не нужно указывать компилятор, make и т.п. Если у вас еще каким-то чудом не стоит, то установите пакет build-essential, а если он уже стоит, откройте файл /usr/share/doc/build-essential/list, в котором находится список пакетов, которые никогда не нужно указывать в зависимостях для сборки. Далее — пакет debhelper. Это пакет, предоставляющий нам многия радости для сборки, от его версии зависит, насколько крутые плюшки мы сможем использовать. Я рекомендую оставить седьмую версию, потому что ее плюшками вы сможете воочию насладиться, когда мы будем писать скрипт для сборки. Ну и libevent-dev, пакет, с которым мы так намучились когда-то. Обязательно — с указанием версии.
Едем дальше. Открываем файл compat, сверяемся со стоящей там цифрой — она должна быть такой же, как версия debhelper в файле control, то есть 7. Зачем он нужен — если честно, сам не знаю, а выяснять лень. Но нужен :)
Открываем файл changelog и приводим его к следующему виду:
darkk-redsocks (2009013101-1) experimental; urgency=low

  * Initial release (Closes: #123456)

 -- Vsevolod Velichko <torkvemada@nigma.ru>  Sat, 31 Jan 2009 04:07:47 +0300

Заметьте, мы изменили релиз на experimental (для убунту, подозреваю, там надо поставить что-то типа jaunty), поскольку нужную версию пакета libevent-dev мы можем взять только там (собственно, оттуда мы ее и качали). Фраза «Closes: #123456» нужна для того чтобы багтрекинговая система дебиан или убунту при добавлении пакета в репозиторий автоматически закрыла баг с соответствующим номером. В случае начального пакетирования, как у нас — это номер «бага» планирования создания пакета — ITP (intend to package). Поскольку подобного бага у нас заведено не было, мы поставим там произвольный номер до тех времен, когда соберемся включать пакет в официальный репозиторий. В дальнейшем мы будем обновлять changelog при помощи уже упомянутой в прошлой статье утилиты «dch», выполняя команду «dch -i».
А сейчас переходим к файлу copyright. Он уже заполнен стандартным шаблоном, нам осталось заполнить детали. Приводим его к такому виду:
This package was debianized by Vsevolod Velichko <torkvemada@nigma.ru> on
Sat, 31 Jan 2009 04:07:47 +0300.

It was downloaded from http://darkk.net.ru/redsocks/

Upstream Author:

    Leonid Evdokimov <leon@darkk.net.ru>

Copyright:

    Copyright © 2009 Leonid Evdokimov

License:

    This program is free software: you can redistribute it and/or modify
    it under the terms of the GNU General Public License as published by
    the Free Software Foundation, either version 3 of the License, or
    (at your option) any later version.

    This program is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
    GNU General Public License for more details.

    You should have received a copy of the GNU General Public License
    along with this program. If not, see <http://www.gnu.org/licenses/>.

The Debian packaging is copyright 2009, Vsevolod Velichko <torkvemada@nigma.ru> and
is licensed under the GPL, see `/usr/share/common-licenses/GPL'.

А вот дальше у нас начинается редактирование файлов, которые при создании пакета за нас будет обрабатывать волшебный пакет debhelper. Первым делом — файл docs. В нём хранится список файлов, которые надо будет установить в каталог документации. В общем случае, когда наш src-пакет создаёт только один бинарный пакет при сборке — этот файл можно так и оставить под названием docs. Но мы, чтобы в возможном будущем не возиться, сразу переименуем его по имени бинарного пакета:
$ mv docs darkk-redsocks.docs

Теперь открываем его и добавляем туда всю нашу документацию:
README
doc/*

Следующий пункт программы — файл примера. Для него мы создаём файл darkk-redsocks.examples и пишем в него:
redsocks.conf.example

Поскольку наш Makefile не умеет устанавливать пакет, то мы еще и создаем файл darkk-redsocks.install. В него мы записываем следующую запись:
redsocks usr/bin/
Заметьте, что перед usr слэш не ставится.
Файлы описали? Чудесно, нам осталось отредактировать последний файл. Открываем в редакторе файл rules и начинаем его нещадно корчевать. Секция configure нам ну ваааще не нужна, у нас исходники этого и не умеют — удаляем её и все упоминания о ней. Оставшийся файл приводим вот к такому элегантному виду:
#!/usr/bin/make -f
# -*- makefile -*-

# Uncomment this to turn on verbose mode.
#export DH_VERBOSE=1

build: build-stamp
build-stamp:
        dh build
        touch $@

clean:
        dh clean

install: build
        dh install
        touch $@

binary-indep: install
        dh binary-indep

binary-arch: install
        dh binary-arch

binary: binary-indep binary-arch
.PHONY: build clean binary-indep binary-arch binary install

Обратите внимание: в исходном файле все вызовы имели вид «dh_что-нибудь», например «dh_install». Это атомарные реакции debhelper'а, про которые вы можете прочитать в соответствующих манах. Мы же используем команды вида «dh install», когда вызов идёт к утилите dh (тоже см. соответствующий ман). Данная утилита вызывает по очереди каждый скрипт из определенной группы, на которую указывает передаваемый параметр. Таким образом, пока у нас довольно простой пакет, большая часть этих вызовов будет гоняться вхолостую при сборке, но зато, стоит нам, например добавить в пакет страницу мана, как достаточно будет создать файл darkk-redsocks.manpages, указать там эту страницу, и при следующей сборке dh сам положит её куда надо, да еще и регистрирующий эту страницу в mandb скрипт добавит.
Итак, мы закончили с правкой файлов. Выходим из каталога debian в родительский каталог и с чувством глубокого удовлетворения набираем:
$ debuild --lintian-opts -i

По запросу пароля подписываем наш получившийся src-пакет, а затем внимательно смотрим. Каталогом выше у нас теперь имеется набор файлов:
darkk-redsocks_2009013101-1_amd64.build — это лог, в который записан весь ход сборки пакета
darkk-redsocks_2009013101-1_amd64.changes — это вспомогательный файл к src-пакету
darkk-redsocks_2009013101-1_amd64.deb — собственно сам собранный пакет под нашу архитектуру
darkk-redsocks_2009013101-1.diff.gz — запакованный дифф-файл, в котором хранятся все наши изменения, по сравнению с оригинальными исходниками. Как правило, это всё содержимое каталога debian, а в нашем случае — помните еще исправленный файл base.c?
darkk-redsocks_2009013101-1.dsc — это главный файл-описание src-пакета
darkk-redsocks_2009013101.orig.tar.gz — ну и это — созданный нами в самом начале архив с исходниками

Кто-то может подумать, что всё, на этом работа завершена. Если вы действительно везунчик, то да. На практике именно на этом заканчивается простая и общая часть и начинаются индивидуальные разборки у каждого со своим пакетом. Ну-ка, промотали свой терминал назад, на процесс сборки пакета. У кого он уже совсем убежал — можете открыть свежесобранный файл darkk-redsocks_2009013101-1_amd64.build (у вас, разумеется, вместо amd64 будет своя архитектура), и смотрим, что нам говорит суровый цензор lintian:
Now running lintian…
W: darkk-redsocks: binary-without-manpage usr/bin/redsocks
N:
N: Each binary in /usr/bin, /usr/sbin, /bin, /sbin or /usr/games should
N: have a manual page
N:
N: Note that though the man program has the capability to check for several
N: program names in the NAMES section, each of these programs should have
N: its own manual page (a symbolic link to the appropriate manual page is
N: sufficient) because other manual page viewers such as xman or tkman
N: don't support this.
N:
N: If the name of the man page differs from the binary by case, man may be
N: able to find it anyway; however, it is still best practice to make the
N: case of the man page match the case of the binary.
N:
N: If the man pages are provided by another package on which this package
N: depends, lintian may not be able to determine that man pages are
N: available. In this case, after confirming that all binaries do have man
N: pages after this package and its dependencies are installed, please add
N: a lintian override.
N:
N: Refer to Debian Policy Manual section 12.1 (Manual pages) for details.
N:
N: Severity: normal; Certainty: possible
N:
Finished running lintian.

А говорит он нам, что к бинарнику нет страницы мануала. Как известно, приличные люди должны каждый бинарник снабдить хотя бы простеньким маном, описывающим, что это такое. А у нас-то в пакете его и нету. выхода тут всегда два: первый — упросить автора программы написать ман. Второй — написать ман и либо упросить автора добавить его в программу, либо класть его в пакет самому, указывая себя в копирайтах.
Но в целом — дальше нам из работы над пакетом остаются только правки и при желании что-то исправить — вдумчивое чтение Debian Policy.

Какие еще подводные камни нас ожидают?


Самый большой и частый камень — это лицензионная чистота. Друзья мои, вы просто не представляете, сколько людей на этом напоролось. Берёте вы программу, собираете её в пакет, а debian-legal вам и говорит: «парень, а ты вообще знаешь, что файлик src/face/ob/table.cpp у вас взят из другой программы, а в копирайтах ты его не указал? А всё содержимое каталога src/super/karambol/ вообще распространяется под несвободной лицензией. Ай-ай-ай». Но допустим, вы исправили ошибку, каким-то чудом уломали автора программы написать свободный аналог вместо несвободного кода и ваш пакет включили в репозиторий. Но через неделю дотошный пользователь обнаруживает: «чувакиии, как же так. У них тут в мессенджере показываются иконки клиентов. А каждый логотип всегда распространяется под лицензией своей программы. Так что вы не имеете права класть в архив иконку несвободного клиента ICQ 6.5». Разумеется, при этих словах debian-legal хмурит очи и метким пинком выкидывает ваш уже было принятый пакет нафиг из репозитория. Именно поэтому кстати (я обещал рассказать), пакет qutIM'а снисходительно приняли в убунту, а я в Debian с ним даже не пытаюсь соваться, пока все лицензионные вопросы не будут решены. За одни только несвободные иконки меня будут гнать тапками через всё коммьюнити.
Другой крайне важной проблемой являются, как ни странно, авторы программ. Молитесь на того автора, которого вы будете легко убеждать принимать исправления, дополнения или еще что-то в апстрим. Потому что такие авторы — большая редкость. Возьмите, например, src-пакет Pidgin'а, полюбуйтесь. В нем лежит большая пачка патчей от debian-сообщества. В апстрим пиджин их не берет. А уж если вы попытаетесь что-то хорошее внести в Gnome… говорят, даже Торвальдсу это удавалось с трудом.
Еще иногда вам могут предъявить какое-нибудь неправильное размещение каталогов или отсутствие или неправильный размер/формат какой-нибудь иконки для ярлыка на программу в кедах — на это очень любит ругаться lintian, а его надо слушать в первую очередь. Но это всё достаточно легкоустранимые баги, а вот первые две проблемы — они действительно серьезные и долговечные.

На этом моменте я с вами прощаюсь аж на несколько дней, в следующий раз я вам всё-таки расскажу, как создать собственный репозиторий и, если успею, как проверять свои пакеты на кошерность при помощи pbuilder.
Tags: debianubuntudebсборка пакетовdfsg
Hubs: Configuring Linux
Total votes 37: ↑37 and ↓0 +37
Comments 19
Comments Comments 19

Popular right now

Top of the last 24 hours