Shared Libs Policy Comments
Пошаговая инструкция по переходу на Shared Libs Policy при смене soname.
В багзилле около пяти сотен багов посвящено файловым конфликтам, возникающим при обновлении библиотек (подсчёт неточный).
Обновление пошагово
Рассмотрим пошагово действия при обновлении на примере условного пакета libfoo, у которого в новой версии поменялся soname (имя библиотеки): libfoo.so.N -> libfoo.so.M
Обновление пакета libfoo
- Берем пакет libfoo из репозитория и обновляем его до новой версии.
- Меняем название бинарного пакета на libfooM.
- Для указания версии библиотеки добавляем в спек
%define abiversion M
- и используем его в названии бинарного пакета:
%package -n libfoo%abiversion
- и в секции %files:
%_libdir/lib%name.so.%abiversion
- (последнее — для подстраховки от случайной смены soname при обновлении пакета).
- Добавляем в libfooM
Provides: libfoo = %version-%release
- (для совместимости с пакетами и пользователями, которые используют имя libfoo.
- Название пакета libfoo-devel оставляем неизменным
- Для указания версии библиотеки добавляем в спек
- Если в новом пакете libfooM будут пересечения по файлам со старым пакетом libfoo (например, был упакован файл /usr/bin/foo, который переехал в libpaperM), проставляем у libfooM конфликт со старой версией:
Conflicts: libfoo < 1.1.28-alt4
- (если пересечение есть и с собранным из libfooN пакетом, указываем
<=
в Conflicts, но такую ситуацию желательно не допускать)
Добавление пакета libfooN
- Делаем копию пакета libfoo из репозитория (то есть старого) под названием libfooN.
- Отключаем в пакете сборку всего, что может конфликтовать по файлам с пакетами новой версии, ведь у нас цель обеспечить возможность одновременной установки libpaperN и libpaperM.
- Добавляем подпакет liboo (единственный, который будет формироваться при сборке).
- Для указания версии библиотеки добавляем в спек
%define abiversion N
- и используем его в секции
%files -n libfoo
: %_libdir/lib%name.so.%abiversion
- (для подстраховки от случайной смены soname при обновлении пакета).
- Указываем Legacy группу для пакета:
Group: System/Legacy libraries
Дополнительные пункты для самопроверки
- При взгляде на исходные пакеты: добавляется новый пакет libfooN (из него собирается бинарный libfoo[1]).
- При взгляде на бинарные пакеты: добавляется новый пакет libfooM (из него собирается бинарный libfooM и libfoo-devel)
- Если библиотека пакуется под SharedLibsPolicy, то в пакете с библиотекой не должно быть ничего, что может потом в дальнейшем начать конфликтовать с файлами из нового пакета этой библиотеки. То есть содержимое /usr/bin должно оказаться в %name-tools, а %_datadir/%name/ — в %name-common (условно).
- Следует придерживаться того правила, чтобы пакет с библиотекой не менял имя, поскольку существует вероятность[2] того, что apt не сможет корректно обработать ситуацию, когда библиотека с конкретным soname переезжает в пакет с другим названием.
- При переходе на SharedLibsPolicy следует исправить все недостатки разбиения по подпакетам — смена soname удобный момент для этого.
- Постепенная пересборка пакетов в репозитории при обновлении пакета.
- Чтобы не общаться с другим мантейнерами на предмет разрешения пересборки их пакетов в вашем большом задании, вы по сути просто собираете новую библиотеку в новый пакет, не нарушая целостность репозитория, а мантейнерам оставляете возможность чинить их пакеты, если они перестают собираться с новой версии библиотеки.
- Необходимость одновременного существования разных версий библиотек в репозитории.
- Библиотека может быть очень известной (например, libpng) и сторонние бинарные программы могут быть привязаны к определённой версии библиотеки, не той,которая основная в репозитории.
- При проблемах обновления с бранча на бранч возможность точечных обновлений чрезвычайно расширяется, т.к. старые библиотеки со старыми SONAME вытеснять никто не будет. Например, возможность обновить один новый пакет foo , зависящий от libname2 не затронет другой старый пакет bar, который зависит от старой версии libname1, которой уже нет в новом репозитории, но еще есть в системе. Если бы пакет со старой и новой версией библиотеки назывался libname, то по цепочке потянулась бы вся борода из других библиотек и пакетов, наткнувшись на какую-нибудь другую проблему обновления.
- SharedLibsPolicy не применим, если пакет содержит множество других файлов, например с данными или плагинами, в пересекающихся каталогах (см. libsane в качестве примера). В этом случае мантейнеру придётся пересобрать в своём задании все зависящие пакеты.
Вынесение утилит в подпакет
Исходя из правила «в пакете с библиотекой не должно быть ничего, что может потом в дальнейшем начать конфликтовать с файлами из нового пакета этой библиотеки», утилиты и прочие неверсионированные файлы (т.е. скорее всего все, кроме собственно библиотеки) должны упаковываться в отдельный подпакет.
К примеру, от пакета libfooM ожидается собственно библиотека, а /usr/bin/foo должен быть упакован в отдельный подпакет, например libfoo-utils или просто foo, в зависимости от важности команды и их количества.
Такой пакет скорее всего будет иметь зависимость на libfoo, но пакет libfoo не должен зависеть от утилит (если библиотека вызывает утилиты, тогда разделение на подпакет не имеет смысла).
Польза от вынесения утилит в подпакет
- Чтобы не было файлового конфликта у любых релизов libfoo, libfooN, libfooM.
- Чтобы тот, кто устанавливал /usr/bin/foo, не потерял его в системе, когда /usr/bin/foo переедет из пакета libfoo в libfooM.
- Минимизация зависимостей пакета с библиотекой. Если /usr/bin/bin это скрипт на python, то в итоге у пакета с библиотекой раздуются зависимости.
Благодарности
За появление этой статьи большая благодарность Глебу, начавшему обсуждение[3] и другим участникам:
- Gleb Fotengauer-Malinovskiy
- Mikhail Tergoev
- Alexey V. Vissarionov
- Sergey V Turchin
- Anton Farygin
Ссылки
- ↑ libfoo, а не libfoo1, чтобы соблюсти условие о том, что библиотека не должна переезжать в пакет с другим названием.
- ↑ glebfm@: Я (как автор того изменения в apt, которое улучшило положение дел) всегда был уверен, что просто сильно уменьшилась вероятность. https://bugzilla.altlinux.org/show_bug.cgi?id=46837#c11
- ↑ https://lore.altlinux.org/devel/ZL7b3jkMiopSSuVX@glebfm.altlinux.org/