Ubuntu logo

Packaging Guide

8. Общие библиотеки

Общие библиотеки — это скомпилированный код, предназначенный для совместного использования несколькими различными программами. Они распространяются в виде файлов .so в /usr/lib/.

Библиотеки экспортируют символы в скомпилированном виде: функции, классы и переменные. У каждой библиотеки также есть название SONAME, включающее номер её версии, но который не обязательно совпадает с официальным номером релиза. Программы компилируются с конкретным SONAME библиотеки. Так, если какой-либо из символов библиотеки был удалён или изменён – небходимо изменить версию с тем, чтобы все зависящие от библиотеки пакеты были перекомпилированы с использованием новой версии. Обычно версии устанавливаются в источнике, и мы используем те же номера версий для двоичных пакетов, называемые “номер ABI”, но в случае, если источник не использует вменяемой версионности, создатели пакетов могут использовать отличную, более традиционную нумерацию.

Библиотеки обычно распространяются апстримом в виде отдельных выпусков. Иногда они распространяются, как часть программы. В последнем случае они могут быть включены в двоичный пакет вместе с программой (это называется bundling), если вы не предполагаете использование этих библиотек другими программами, но чаще их всё же следует выделять в отдельные двоичные пакеты.

Сами библиотеки помещаются в двоичный пакет с именем libfoo1, где foo — имя библиотеки, а 1 — версия из SONAME. Файлы разработки из пакета, такие как заголовочные файлы, необходимые для компиляции программ с библиотекой, помещаются в пакет с именем libfoo-dev.

8.1. Пример

В качестве примера мы используем libnova:

$ bzr branch ubuntu:trusty/libnova
$ sudo apt-get install libnova-dev

Чтобы найти SONAME библиотеки, выполните:

$ readelf -a /usr/lib/libnova-0.12.so.2 | grep SONAME

SONAME в данном случае libnova-0.12.so.2, что соответствует имени файла (как правило, но не всегда). Здесь апстрим поместил номер версии из апстрима, как часть SONAME, и задал ABI-версию 2. Имена библиотечных пакетов должны следовать SONAME библиотеки, которую они содержат. Двоичный библиотечный пакет называется libnova-0.12-2, где libnova-0.12 — имя библиотеки, а 2 — наш ABI-номер.

Если авторы из апстрима внесли несовместимые изменения в свою библиотеку, они должны изменить номер версии SONAME, а мы должны переименовать нашу библиотеку. Любые другие пакеты, использующие наш библиотечный пакет, нужно будет перекомпилировать с новой весрией, это называется переходом (transition) и требует некоторых усилий. Надо надеяться, наш ABI-номер продолжит соответствовать SONAME апстрима, но иногда они вносят несовместимости без изменения их номера версии, а нам нужно изменить наш.

Взглянув на debian/libnova-0.12-2.instal, мы увидим, что он включает в себя два файла:

usr/lib/libnova-0.12.so.2
usr/lib/libnova-0.12.so.2.0.0

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

libnova-dev.install содержит все файлы, необходимые для компиляции программы с данной библиотекой. Заголовочные файлы, бинарник конфигурации, файл libtool’a .la, а также libnova.so – ещё один симлинк на библиотеку, создаваемый с тем, чтобы программы могли компилироваться вне зависимости от старшего номера версии (при этом, скомпилированное приложение всё равно будет зависеть от версии).

.la-файлы libtool’а требуются на некоторых не-Linux системах с ограниченной поддержкой библиотек, но на системах Debian зачастую создают больше проблем, чем решают. Цель Debian отказаться от .la-файлов сегодня весьма актуальна, и вы можете помочь с решением этой задачи.

8.2. Статические библиотеки

Пакет -dev также содержит usr/lib/libnova.a. Это статическая библиотека, альтернатива общей библиотеке. Любая программа, скомпилированная со статической библиотекой, содержит её код непосредственно в себе. Это позволяет не беспокоиться о двоичной совместимости библиотеки. Однако это также означает, что любые ошибки, в том числе уязвимости в безопасности, не будут исправлены за счёт обновления библиотеки, пока программа не будет перекомпилирована. По этой причине использовать программы со статическими библиотеками не рекомендуется.

8.3. Символьные файлы

Когда приложение компилируется с библиотекой, механизм shlibs добавит к пакету зависимость от этой библиотеки. Именно поэтому большинство программ содержат Depends: ${shlibs:Depends} в файле debian/control. Этот максов заменяется списком зависимых библиотек при билде. Однако shlibs может только указывать зависимость от старшей ABI-версии , 2 в нашем примере с libnova, так что если новые символы будут добавлены в будущей libnova 2.1 – приложение будет запускаться и с более старой версией libnova ABI 2.0, что приведёт к аварианому завершению.

Чтобы точнее указывать зависимости от библиотек, мы создали файл .symbols, который перечисляет все символы библиотеки и версии, в которых они появились.

libnova не имеет символьного файла, так что мы можем создать его. Начните с компиляции пакета:

$ bzr builddeb -- -nc

Опция -nc указывает не удалять сборочные файлы после завершения компиляции. Перейдите в каталог сборки и выполните dpkg-gensymbols для пакета библиотеки:

$ cd ../build-area/libnova-0.12.2/
$ dpkg-gensymbols -plibnova-0.12-2 > symbols.diff

Это создаст diff-файл, который вы сможете применить самостоятельно:

$ patch -p0 < symbols.diff

Это создаст файл с именем вида dpkg-gensymbolsnY_WWI, в котором будут перечислены все символы. Он также указывает текущую версию пакета. Версию пакета можно убрать из файла, так как новые символы обычно добавляются не с новой версией пакета, а разработчиками исходной библиотеки.

$ sed -i s,-0ubuntu2,, dpkg-gensymbolsnY_WWI

Теперь переместите файл туда, где он должен находиться, зафиксируйте изменения и выполните тестовую сборку:

$ mv dpkg-gensymbolsnY_WWI ../../libnova/debian/libnova-0.12-2.symbols
$ cd ../../libnova
$ bzr add debian/libnova-0.12-2.symbols
$ bzr commit -m "add symbols file"
$ bzr builddeb

Если компиляция выполняется успешно, значит символьный файл не содержит ошибок. С выходом следующей апстрим-версии libnova вам придётся снова запустить dpkg-gensymbols, чтобы создать diff для обновления символьного файла.

8.4. Символьные файлы библиотек C++

У языка C++ более строгие стандарты на двоичную совместимость, чем у C. Команда Debian Qt/KDE поддерживает некоторые скрипты, которые помогут справиться с этим: страница Работа с файлами symbols описывает принципы их использования.

8.5. Информация для дальнейшего чтения

Статья Junichi Uekawa Пакетирование библиотек для Debian рассматривает этот вопрос более детально.