Shared Libs Policy
Под библиотекой будем понимать .so файл, предназначенный для совместного использования многими программами. Под действие данного полиси не попадают .so файлы, которые явно загружаются конкретной программой (плагины).
Библиотеки могут потенциально использоваться многими программами, из-за чего несовместимое изменение интерфейса любой библиотеки требует большого объёма работы по адаптации её клиентов. Для упрощения процесса обновления и уменьшения количества сломанных в каждый момент времени пакетов библиотеки различных несовместимых версий должны уметь сосуществовать в установленной системе.
В дальнейшем несовместимое изменение ABI библиотеки будет называться «ломкой».
Полиси одной строкой:
не стоит класть новый soname в пакет с тем же именем (где лежал старый soname).
Упаковка библиотек
Библиотека должна быть упакована в пакет, имя которого меняется при каждой ломке ABI.
Пакет должен иметь название lib%name%abiversion, где %abiversion является изменяемой частью (если название библиотеки заканчивается на цифру, то во всех именах пакетов перед %abiversion нужно добавить '_': lib%{name}_%{abiversion}, lib%{name}_%{abiversion}-devel etc).
development-часть библиотек должны быть выделены в отдельный пакет, который должен иметь название lib%name-devel. Если планируется поддерживать несколько development-версий для разных версий библиотек (что далеко не всегда оправданно, см. ниже) то lib%name%abiversion-devel.
Под development-частями библиотеки понимаются не только headers, но и при наличии у библиотеки soname - симлинк с расширением .so (без soname), используемый для линковки с данной библиотекой.
Исключение составляют .so файлы, которые используются не как библиотеки, а как плагины (явно загружаются в память приложением). Примером является пакет tomcat-native, у которого libtcnative-1.so не используется для линковки. О известных исключениях такого рода необходимо сообщать в Bugzilla на тест altlinux-policy-shared-lib-contains-devel-so.
Статические библиотеки, собираемые в дополнение к динамическим, должны быть выделены в отдельный пакет lib%name-devel-static или lib%name%abiversion-devel-static (сооветственно стилю -devel-пакета). Если же собирается только статическая библиотека, без динамической, то пакет должен называться -devel.
Таким образом, именование пакетов вида lib%name%abiversion и lib%name-devel позволит избавиться от проблем с обновлениями пакетов, когда они не пересобраны с новой библиотекой.
Если же библиотеки с разным ABI сосуществовать в системе не могут по каким-то причинам (будь то файловые конфликты или что-то другое), то данное полиси неприменимо, поскольку содержание двух пакетов в репозитории не будет иметь смысла и майнтайнер при обновлении библиотеки вместо изменения названия пакета должен пересобрать все зависимые пакеты.
Выбор правильного %abiversion в имени пакета
Если авторы библиотеки явно используют soversion для указания моментов ломки, то в качестве %abiversion нужно использовать именно его. Если авторы библиотеки soversion не используют, или используют нестандартно (скажем, изменяя его вне зависимости от реальной смены ABI), то можно использовать любую другую удобную в данном конкретном случае схему именования (рекомендуется использовать последовательно возрастающие числа, начинающиеся с 0 и увеличивающиеся на 1 при каждой ломке).
В случае, если существует несколько поддерживаемых веток одной библиотеки, %soversion может соответствовать major-версии библиотеки (libqt3, libqt4) или иметь вид major.minor (libdb4.0, libdb4.1). Можно также использовать часть soname’а библиотеки (напр., libcurl4, libflac8).
Переезд со старого именования
Не секрет, что сейчас в Сизифе подобным образом запакованы очень немногие библиотеки. Предположим, что библиотека libfoo обновилась и в ней сменился soname с N на M.
При сборке новой версии пакета libfoo предлагается сделать следующее:
- Переименовать бинарный пакет libfoo в libfooM
Политика адаптации клиентов разделяемых библиотек к новым версиям
За исключением особых случаев (например, qt3 и qt4, которые по сути являются различными библиотеками, а не разными версиями одной), настоятельно рекомендуется поддерживать наличие ровно одного -devel пакета (соответствующего самой новой версии библиотеки) для любой библиотеки, сколько бы старых версий этой библиотеки не присутствовало в Сизифе. При выполнении этого правила новые собираемые версии клиентов библиотек будут автоматически собираться с новой версией библиотеки (см. тж. письмо в devel@). В виде исключения, если новая версия библиотеки приводит к несобираемости большого количества пакетов, допустимо поддерживать две версии пакетов -devel, с проставлением тегов Conflicts в этих пакетах -devel друг на друга и соответствующим разделением зависимых пакетов на собирающиеся с новой и со старой версией библиотеки.
Старые библиотеки должны быть перемещены в группу 'System/Legacy libraries' при появлении в Сизифе новой версии. Аналогично пакетам -devel, в исключительных случаях разрешается иметь более одной версии библиотеки не в Legacy.
Когда библиотека из группы 'System/Legacy libraries' не требуется ни одним пакетом из Сизифа, она должна быть удалена из него. Пакеты из группы 'System/Legacy Libraries' (и, соответственно, пакеты, зависящие от них) объявляются непригодными к выпуску в стабильной ветке.
Бэкпорты
Поскольку предлагаемое изменение именования библиотек жёстко прикрепляет soname к имени пакета, а также позволяет сосуществовать разным версиям библиотек, становится возможным бэкпортить новые версии библиотек и программы, зависящие от новых версий библиотек, что значительно ослабляет условие 5 в backports policy.
Область применимости
SharedLibsPolicy рассчитывает на то, что API не меняется. В случае смены API лучше делать ещё и два devel-пакета - для возможности сборки и со старой, и с новой библиотекой. При этом такие devel-пакеты вполне могут конфликтовать между собой, одновременную установку обязательно обеспечивать только для runtime-части.
Для нового пакета вида libfooM-devel желательно сделать
Provides: libfoo-devel = %version
чтобы обеспечить возможность указания в спеке зависимость без версии (это особенно удобно, если версия часто меняется).
Примечания
Если оставить старое название, можно столкнуться с багофичей apt: он плохо переносит переименования пакетов в случае, когда содержимое старой версии пакета переносится в пакет с новым именем, но при этом пакет со старым именем остаётся существовать; порой приходится разделять обновление на задания, чтобы сперва «физически» провести удаление (под)пакета.
После проведения начального перехода на новую версию ABI обычно пробуют удалить старую версию библиотеки для получения списка собранных с ней пакетов (т.е. делают compat-сборку, чтобы не переусложнять задание с обновкой, затем пересобирают клиентов с новой -- это может быть более растянутый во времени процесс, вплоть до ожидания исправлений в соответствующих апстримах; и затем, если нет веских поводов вроде необходимости долгосрочного сохранения важной части ABI, старую версию удаляют уже не в пробном режиме).
Стоит иметь в виду, что параллельные версии библиотек могут приводить к неочевидным ошибкам в случае непрямого попадания в адресное пространство одного итогового процесса (например, приложение A связано с библиотеками libX и libY, при этом libX связана с libZ1, а libY — с libZ2).