[Из песочницы] Еще раз о deb пакетах

Deb пакеты очень удобный инструмент, особенно если знаешь как его использовать. Попробую поделиться собственным опытом в данном вопросе.

Подготовка


Чтобы начать создавать deb пакеты, нужно установить несколько пакетов:

$ sudo apt-get install dh_make


Подготовка папки с исходниками


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

Папка должна называться имяпакета-версия. Т.е. если у меня есть папка Plugins с программой версии 0.1, то я создаю папку с именем plugins-0.1.

$ ls
VKSPlugins
$ mv VKSPlugins/ libvksplugins-0.1
$ ls
libvksplugins-0.1


Теперь нужно создать архив с этой папкой. Архив должен содержать в имени *.orig.tar.gz, т.е.:

$ tar -zcf libvksplugins_0.1.orig.tar.gz libvksplugins-0.1
$ ls
libvksplugins-0.1 libvksplugins_0.1.orig.tar.gz


Последний подготовительный шаг, это создание в папке с исходниками папки debian со множеством служебных файлов. Чтобы это сделать, нужно выполнить команду:

$ cd libvksplugins-0.1/
$ dh_make
Type of package: single binary, indep binary,
multiple binary, library, kernel module, kernel patch?
[s/i/m/l/k/n] l
Maintainer name : User Name
Email-Address : user@name.ru
Date : Wed, 19 Aug 2015 14:55:53 +0300
Package Name : libvksplugins
Version : 0.1
License : blank
Type of Package : Single
Hit  to confirm:
Skipping creating ../libvksplugins_0.1.orig.tar.gz because it already exists
Done. Please edit the files in the debian/ subdirectory now. plugins
uses a configure script, so you probably don’t have to edit the Makefiles.


В процессе выполнения этой команды будет задан вопрос о том, какой тип архива мы создаем, самый простой это single.

О типе пакета

На самом деле документация говорит, выбирать вариант только single. Т.к. я не смог понять всех требований к пакету типа library, но меня вполне устраивает результат, то описание и дальше пойдет про пакет типа library.


Настройка пакета


Вся настройка пакета происходит путем редактирования файлов в каталоге debian. Рассмотрим те файлы, которые будем использовать:

  • changelog — история пакета.
  • control — главный конфиг пакета;
  • rules — аналог Makefile для пакета;


Кроме этих файлов, в папке debian будет создано много файлов *.ex которые являются примерами для конфигурации различных вещей, но мы не будем их использовать и поэтому их нужно удалить.

changelog


Данный файл содержит историю изменения пакета и текущую версию пакета. Посмотрим на его содержимое:

$ cat changelog
libvksplugins (0.1-1) unstable; urgency=low

* Initial release (Closes: #nnnn) 

-- User Name  Wed, 19 Aug 2015 15:03:51 +0300


В начале идет название пакета — libvksplugins, затем его версия. Версия делиться на две части символом »-». Первая часть показывает версию программы в пакете, вторая «ревизию» пакета. Ревизия это версия пакета, т.е. если раньше такого пакета не было, то ревизия равна 1. Если же пакет с такой версией программы уже был, но в нем произошли изменения, то ревизия увеличивается.

Слово unstable показывает, что пакет является не стабильным, т.е. он не был протестирован должным образом на машинах пользователей.

Надпись urgency=low показывает срочность изменения. Т.к. срочности нет, то значение равно low. Если бы, мы делали пакет для исправления серьезной уязвимости или ошибки, то значение можно было бы установить в high.

После первой строки идет пустая строка, а за ней первая запись:

* Initial release (Closes: #nnnn) 


В Debian, changelog используется для автоматического закрытия ошибок в системах отслеживания ошибок в программных продуктах. Т.к. в данном случае, я не использую такую систему, то эта строка принимает вид:

* Initial release

Замечание

При проверке пакета программой lintian, отсутствие Closes: #XXXX считается ошибкой.


Последняя строка является подписью человека, сделавшего запись. В ней содержится имя и адрес, а также дата изменения.

После установки deb пакета, файл changelog устанавливается в

/usr/share/doc/<пакет>/changelog.Debian.gz

control


Файл debian/control является главным конфигом, при создании deb пакета. Вот пример такого файла:

$ cat control
Source: libvksplugins
Priority: optional
Maintainer: User Name 
Build-Depends: debhelper (>= 9), cmake
Standards-Version: 3.9.5
Section: libs
Homepage: 
#Vcs-Git: git://anonscm.debian.org/collab-maint/plugins.git
#Vcs-Browser: http://anonscm.debian.org/?p=collab-maint/plugins.git;a=summary

Package: libvksplugins-dev
Section: libdevel
Architecture: any
Depends: libvkspluginsBROKEN (= ${binary:Version}), ${misc:Depends}
Description: 
 

Package: libvkspluginsBROKEN
Architecture: any
Depends: ${shlibs:Depends}, ${misc:Depends}
Description: 
 


Видно, что файл разбит на секции при помощи пустых строк. Каждая секция описывает один пакет, создаваемый из папки с исходниками. Рассмотрим их по порядку:

Source Данная секция говорит о том, что нужно создать пакет исходных кодов. Параметром указано libvksplugins, это значит, что пакет исходных кодов будет называться libvksplugins.

Priority Эта секция устанавливает приоритет пакета. Т.к. система может прекрасно обойтись без нового пакета, то значение секции установлено в optional. Т.е. этот пакет не обязателен для установки. Подробнее о приоритетах написано здесь.

Maintainer Эта секция описывает контакты человека, создающего пакет. Ее формат довольно прост и дополнительного описание не требует.

Build-Depends Одна из самых важных секций, устанавливающая зависимости пакета. Зависимости, указанные в данной секции должны быть выполнены, чтобы можно было собрать пакет. Т.е. список зависимостей для сборки и установки могут отличаться.

Видно, что в зависимостях стоят debhelper (>= 9), cmake. Зависимость debhelper (>= 9) ставиться для всех пакетов по умолчанию. Она нужна для корректной работы программ вида dh_*.

Второй элемент cmake был добавлен потому, что папка с исходниками содержала файл CMakeLists.txt, т.е. для сборки используется система сборки CMake. Для того, чтобы узнать, какие зависимости есть у программы, можно почитать ее документацию. Кроме этого, можно воспользоваться командой dpkg-depcheck. Данная команда должна запускаться так:

$ dpkg-depcheck -d ./configure


Но, т.к. при использовании CMake нет скрипта конфигурирования, то я использую ее так:

$ mkdir build && cd build
$ dpkg-depcheck -d cmake ../
.....
Packages needed:
libxml2:amd64
cmake
libkrb5support0:amd64
language-pack-ru-base
libnettle4:amd64
.....
libedit2:amd64
libtasn1-6:amd64
qt4-qmake
libgssapi-krb5-2:amd64
libhcrypto4-heimdal:amd64
.....
libroken18-heimdal:amd64
libsqlite3-0:amd64
libqt4-dev
libssl1.0.0:amd64
.....


Из примечательных тут можно отметить:

cmake
qt4-qmake
libqt4-dev

Остальные являются зависимостями данных. Причем, cmake уже есть в списке зависимостей сборки. В принципе, можно его оставить как есть или указать используемую версию:

$ apt-cache show cmake | grep Version:
Version: 2.8.12.2-0ubuntu6


При этом в CMakeLists.txt указана версия cmake, которую нужно использовать:

$ cat CMakeLists.txt | grep cmake_minimum
cmake_minimum_required(VERSION 2.8.4)


Я думаю, что разработчику виднее, и поэтому указываю версию из CMakeLists.txt. Для Qt 4 все понятно с номерами версий, но для очистки совести проверим и их версии:

$ apt-cache show qt4-qmake | grep Version:
Version: 4:4.8.6+git49-gbc62005+dfsg-1ubuntu1.1
Version: 4:4.8.6+git49-gbc62005+dfsg-1ubuntu1
$ apt-cache show libqt4-dev | grep Version:
Version: 4:4.8.6+git49-gbc62005+dfsg-1ubuntu1.1
Version: 4:4.8.6+git49-gbc62005+dfsg-1ubuntu1


Т.е. для Qt 4 указываем версию 4.8.6:

Build-Depends: debhelper (>= 9), cmake (>= 2.8.4), qt4-qmake (>= 4.8.6), libqt4-dev (>= 4.8.6)


Standards-Version Версия стандарта, в соответствии с которым создан файл. Это значение не нужно менять.

Section. Секция для пакета, т.е. группа пакетов, выполняющая одну задачу. В Политике Debian разделе 2.4 этот вопрос описан более подробно.

Homepage Домашняя страница проекта. Т.к. данный код писал я и у него нет страницы, просто удаляю эту строку.

Vcs-* Ссылки на репозитории проекта. Их у меня тоже нет, поэтому удаляю эти строки.

Другие пакеты После секции файла, где описывается пакет с исходниками, идут секции, которые описывают другие пакеты, создаваемые из пакета с исходниками. Схема создания пакетов:

1c09c931dc394efb9bb05160854df511.png

Из схемы видно, что из исходников программы, я хочу получить 4 пакета:

  • пакет с исходными кодами;
  • пакет с бинарником (самой библиотекой);
  • пакет для разработки (заголовочные файлы);
  • пакет с документацией.


Возникает вопрос, зачем так много пакетов? Ответов на него может быть несколько, если прочитать соответствующие обсуждения на stackoverflow.com то основная идея разбиения в том, что большинству пользователей не нужны заголовочные файлы и документация, поэтому разделение этих файлов способствует снижению нагрузки на сеть и скорости установки программ.

Мой персональный ответ на данный вопрос, заключается в том, что такое разбиение помогает структурировать программу по тому, как я хочу с ней работать. Для разработки я поставлю dev пакет, а для использования нет.

Кроме описанных выше пакетов, можно создать dbg пакет с отладочной сборкой программы. Это может пригодиться, если программа падает и у Вас есть под рукой отладчик. Однако, я так и не смог понять как это делать. Документация не дает ответа на этот вопрос. Если делать так как описано в ней, то я либо получаю пустой пакет либо получаю кучу ошибок при сборке.

Схема на рисунке выше показывает, что пакет с исходниками называется libvksplugins_source, однако, в файле control указано, что пакет с исходниками будет называться libvksplugins. На самом деле, он действительно будет называться libvksplugins, а пакет с бинарниками, будет называться libvksplugins… deb. Суть этой путаницы в том, что пакет с исходниками представляет собой tar архив и служебные файлы, тогда как пакет бинарников это архив с расширение deb.

Настройка пакета библиотеки Посмотрим внимательно на описание пакета библиотеки:

Package: libvksplugins
Architecture: any
Depends: ${shlibs:Depends}, ${misc:Depends}
Description: Library for creating plugins with VKS 2
This library provides a mechanism for creating plugins
to use in project VKS 2.

Параметр Architecture устанавливает архитектуру собираемого пакета. Значение any означает, что после сборки бинарников нужная архитектура будет подставлена системой сборки. Т.е. на 64х битной машине, получится пакет …_amd64…, а на 32х битной пакет …_i386….

Для пакетов, содержащих скрипты или тексты, нужно указывать значение как all.

Третья строка, описывает зависимости создаваемого пакета. Вот как она описана в 4й главе Руководства начинающего разработчика Debian:

Утилита dh_shlibdeps вычисляет зависимости двоичного пакета от общих библиотек. Она генерирует список исполняемых файлов ELF и общих библиотек, которые находит для каждого двоичного пакета. Этот список подставляется вместо ${shlibs: Depends}.

Утилита dh_perl вычисляет зависимости Perl. Она генерирует список зависимостей от perl или perlapi для каждого двоичного пакета. Этот список подставляется вместо ${perl: Depends}.

Некоторые команды пакета debhelper могут добавлять зависимости к вашему генерируемому пакету. Каждая команда генерирует список необходимых пакетов для каждого двоичного пакета. Этот список подставляется вместо
${misc: Depends}.

Утилита dh_gencontrol генерирует файл DEBIAN/control для каждого двоичного пакета, заменяя ${shlibs: Depends}, ${perl: Depends}, ${misc: Depends} и т.д на полученные значения.


Т.е. эта строка говорит о том, что сборщик пакета сам определит зависимости.

Последний раздел данной секции это описание пакета. Первая строка содержит кратное описание, последующие строки содержат более подробное описание. Подробное описание, должно иметь определенный формат:

  • строка должна начинаться с пробела;
  • строка не должна быть длиннее 80 символов;
  • пустая строка должна начинаться с пробела и состоять из символа точки.


Настройка пакета заголовочных файлов Пакет с заголовочными файлами, будет называться libvksplugins-dev, вот его описание:

Package: libvksplugins-dev
Section: libdevel
Architecture: any
Depends: libvksplugins (= ${binary:Version}), ${misc:Depends}
Description: Development package for libvksplugins
This package provides development files for
library libvksplugins.
.
Also, it contains pkg-config file, to use.

В данном примере, интересна строка Depends. В ней указано, что данный пакет будет зависеть от пакета библиотеки libvksplugins, причем (= ${binary: Version}) говорит о том, что необходимо строгое совпадение версий бинарного пакета и пакета разработчика. Это важный момент потому, что заголовочные файлы должны строго соответствовать бинарникам.

Настройка пакета документации Вместе с библиотекой поставляется документация, чтобы она была в отдельном пакете, добавляем его описание:

Package: libvksplugins-doc
Architecture: all
Depends: ${shlibs:Depends}, ${misc:Depends}
Description: Documentation for libvksplugins
Package contains html documentation files for libvksplugins

Тут должно быть все понятно.

rules


Данный файл является аналогом Makefile для сборки пакетов. По умолчанию, он создается в таком виде:

$ cat rules
#!/usr/bin/make -f
# See debhelper(7) (uncomment to enable)
# output every command that modifies files on the build system.
#DH_VERBOSE = 1
# see EXAMPLES in dpkg-buildflags(1) and read /usr/share/dpkg/*
DPKG_EXPORT_BUILDFLAGS = 1
include /usr/share/dpkg/default.mk
# see FEATURE AREAS in dpkg-buildflags(1)
#export DEB_BUILD_MAINT_OPTIONS = hardening=+all
# see ENVIRONMENT in dpkg-buildflags(1)
# package maintainers to append CFLAGS
#export DEB_CFLAGS_MAINT_APPEND = -Wall -pedantic
# package maintainers to append LDFLAGS
#export DEB_LDFLAGS_MAINT_APPEND = -Wl,--as-needed
# main packaging script based on dh7 syntax
%:
      dh $@
# debmake generated override targets
# This is example for Cmake (See http://bugs.debian.org/641051 )
#override_dh_auto_configure:
# dh_auto_configure -- \
# -DCMAKE_LIBRARY_PATH=$(DEB_HOST_MULTIARCH)


Видно, что это bash скрипт с синтаксисом Makefile. Единственная интересная конструкция здесь это

%:
     dh $@


Это шаблон, который для всех целей вызывает dh команду с передачей аргументов ей. Для сборки пакета важно, чтобы текст dh $@ начитался с символа табуляции. Т.е. отступ это не пробелы, а табуляция.

Т.к. исходники используют систему сборки CMake, то нужно изменить эту запись следующим образом:

%:
     dh $@ --buildsystem=cmake


Содержимое пакетов


После того, как мы указали в debian/control какие пакеты мы хотим получить, нужно указать какие файлы в какой пакет помещать. Для этого, для каждого названия пакета из файла control, нужно создать в папке debian два файла. Первый должен называться пакет.dirs, а второй пакет.install. Суть файлов в том, что первый указывает, какие папки нужно создать для пакета, а второй, какие файлы включить в пакет.

Посмотрим на их содержимое:

$ cat libvksplugins-dev.dirs
usr/lib
usr/include
$ cat libvksplugins-dev.install
usr/include/*
usr/lib/lib*.a
usr/lib/lib*.so
usr/lib/pkgconfig/*
usr/share/pkgconfig/*


Важный момент, отсутствие начальной дроби в путях и отсутствие дроби в конце пути к папке. Проверив, куда CMake устанавливает файлы библиотеки, можно сформировать такие файлы:

$ for item in $(ls libvksplugins*); do echo "$item:"; cat $item; done
libvksplugins-dev.dirs:
usr/include/dep572
usr/lib/pkgconfig

libvksplugins-dev.install:
usr/include/dep572/plugins/*
usr/lib/dep572/lib*.so
usr/lib/pkgconfig/*

libvksplugins.dirs:
usr/lib/dep572

libvksplugins-doc.dirs:
usr/share/doc/libplugins-0.1

libvksplugins-doc.install:
usr/share/doc/libplugins-0.1/*.tgz

libvksplugins.install:
usr/lib/dep572/lib*.so.*


Завершение настройки


Т.к. исходники мои, то никаких дополнительных описаний и ограничений copyright у меня нет, поэтому я удаляю все лишние файлы из каталога debian.

Сборка пакетов


После настройки, сборка пакетов происходит довольно просто, нужно в папке проекта (которая включает подпапку debian) выполнить команду:

$ dpkg-buildpackage -rfakeroot -us -uc


Параметры -us -uc говорят о том, что не нужно подписывать gpg ключом созданные пакеты. Их можно не использовать, если настроен ключ подписи gpg по умолчанию. Как указать ключ подписи по умолчанию, я тоже не понял. Если все прошло хорошо, то у нас поваляется набор пакетов в папке выше:

$ ls -l ../
итого 748
drwxrwxr-x 10 user user   4096 авг.  20 10:46 libvksplugins-0.1
-rw-rw-r--  1 user user   2210 авг.  20 10:47 libvksplugins_0.1-1_amd64.changes
-rw-r--r--  1 user user   6418 авг.  20 10:47 libvksplugins_0.1-1_amd64.deb
-rw-rw-r--  1 user user   1504 авг.  20 10:46 libvksplugins_0.1-1.debian.tar.xz
-rw-rw-r--  1 user user   1008 авг.  20 10:46 libvksplugins_0.1-1.dsc
-rw-rw-r--  1 user user  36713 авг.  19 14:52 libvksplugins_0.1.orig.tar.gz
-rw-r--r--  1 user user   3262 авг.  20 10:47 libvksplugins-dev_0.1-1_amd64.deb
-rw-r--r--  1 user user 699564 авг.  20 10:47 libvksplugins-doc_0.1-1_all.deb


Заключение


Если вы дочитали до сюда — значит вы любите читать.

Этот текст является результатом моего опыта внедрения deb пакетов на работе. Опыт показал, что наличие сетевого репозитория (reprepro) и внимательное отслеживание версий, позволяют без проблем обновлять и тестировать различные версии ПО на парке из 30 машин с системами Astra Linux 1.3, 1.4 и Эльбрус ОС.

© Habrahabr.ru