Shared Libs Policy Comments: различия между версиями

Материал из ALT Linux Wiki
 
(не показано 6 промежуточных версий 2 участников)
Строка 1: Строка 1:
[[Файл:Libpaper0.png|безрамки|right|link=Shared Libs Policy Versioning Example|Shared Libs Policy Versioning Example]]


Пошаговая инструкция по переходу на Shared Libs Policy при смене soname.
Пошаговая инструкция по переходу на Shared Libs Policy при смене soname.
Строка 7: Строка 8:


Рассмотрим пошагово действия при обновлении на примере условного пакета libfoo, у которого в новой версии поменялся soname (имя библиотеки):
Рассмотрим пошагово действия при обновлении на примере условного пакета libfoo, у которого в новой версии поменялся soname (имя библиотеки):
libfoo.so.N -> libfoo.so.M
<code>libfoo.so.N -> libfoo.so.M</code>.


==== Обновление пакета libfoo ====
==== Обновление пакета libfoo ====
Строка 19: Строка 20:
##: <code>%_libdir/lib%name.so.%abiversion</code>
##: <code>%_libdir/lib%name.so.%abiversion</code>
##:(последнее — для подстраховки от случайной смены soname при обновлении пакета).
##:(последнее — для подстраховки от случайной смены soname при обновлении пакета).
## Добавляем в libfooM
<!--## Добавляем в libfooM
##: <code>Provides: libfoo = %version-%release</code>
##: <code>Provides: libfoo = %version-%release</code>
##:(для совместимости с пакетами и пользователями, которые используют имя libfoo.
##:(для совместимости с пакетами и пользователями, которые используют имя libfoo).-->
## Название пакета libfoo-devel оставляем неизменным
## Название пакета libfoo-devel оставляем неизменным
# Если в новом пакете libfooM будут пересечения по файлам со старым пакетом libfoo (например, был упакован файл /usr/bin/foo, который переехал в libfooM), проставляем у libfooM конфликт со старой версией:
# Если в новом пакете libfooM будут пересечения по файлам со старым пакетом libfoo (например, был упакован файл /usr/bin/foo, который переехал в libfooM), проставляем у libfooM конфликт со старой версией:
Строка 30: Строка 31:
# Делаем копию пакета libfoo из репозитория (то есть старого) под названием libfooN.
# Делаем копию пакета libfoo из репозитория (то есть старого) под названием libfooN.
# Отключаем в пакете сборку всего, что может конфликтовать по файлам с пакетами новой версии, ведь у нас цель обеспечить возможность одновременной установки libfooN и libfooM.
# Отключаем в пакете сборку всего, что может конфликтовать по файлам с пакетами новой версии, ведь у нас цель обеспечить возможность одновременной установки libfooN и libfooM.
# Добавляем подпакет libfoo (единственный, который будет формироваться при сборке).
# Оставляем только подпакет libfoo (единственный, который будет формироваться при сборке).
# Для указания версии библиотеки добавляем в спек
# Для указания версии библиотеки добавляем в спек
#: <code>%define abiversion N</code>
#: <code>%define abiversion N</code>
Строка 48: Строка 49:
glebfm@: Я (как автор того изменения в apt, которое улучшило положение дел) всегда был уверен, что просто сильно уменьшилась вероятность. https://bugzilla.altlinux.org/show_bug.cgi?id=46837#c11</ref> того, что apt не сможет корректно обработать ситуацию, когда библиотека с конкретным soname переезжает в пакет с другим названием.
glebfm@: Я (как автор того изменения в apt, которое улучшило положение дел) всегда был уверен, что просто сильно уменьшилась вероятность. https://bugzilla.altlinux.org/show_bug.cgi?id=46837#c11</ref> того, что apt не сможет корректно обработать ситуацию, когда библиотека с конкретным soname переезжает в пакет с другим названием.
# При переходе на SharedLibsPolicy следует исправить все недостатки разбиения по подпакетам — смена soname удобный момент для этого.
# При переходе на SharedLibsPolicy следует исправить все недостатки разбиения по подпакетам — смена soname удобный момент для этого.
# Добавлять в libfooM провайд <code>libfoo = %version-%release</code> не следует, поскольку для зависимостей между пакетами это только внесёт путаницу, а вручную обычно библиотеки не устанавливают (в отличие от devel-пакетов).




Строка 74: Строка 77:
* Чтобы не было файлового конфликта у любых релизов libfoo, libfooN, libfooM.
* Чтобы не было файлового конфликта у любых релизов libfoo, libfooN, libfooM.
* Чтобы тот, кто устанавливал /usr/bin/foo, не потерял его в системе, когда /usr/bin/foo переедет из пакета libfoo в libfooM.
* Чтобы тот, кто устанавливал /usr/bin/foo, не потерял его в системе, когда /usr/bin/foo переедет из пакета libfoo в libfooM.
* Минимизация зависимостей пакета с библиотекой. Если /usr/bin/bin это скрипт на python, то в итоге у пакета с библиотекой раздуются зависимости.
* Минимизация зависимостей пакета с библиотекой. Если /usr/bin/foo это скрипт на python, то в итоге у пакета с библиотекой раздуются зависимости.


=== Благодарности ===
=== Благодарности ===

Текущая версия от 03:17, 4 августа 2023

Shared Libs Policy Versioning Example

Пошаговая инструкция по переходу на Shared Libs Policy при смене soname.

В багзилле около пяти сотен багов посвящено файловым конфликтам, возникающим при обновлении библиотек (подсчёт неточный).

Обновление пошагово

Рассмотрим пошагово действия при обновлении на примере условного пакета libfoo, у которого в новой версии поменялся soname (имя библиотеки): libfoo.so.N -> libfoo.so.M.

Обновление пакета libfoo

  1. Берем пакет libfoo из репозитория и обновляем его до новой версии.
  2. Меняем название бинарного пакета на libfooM.
    1. Для указания версии библиотеки добавляем в спек
      %define abiversion M
      и используем его в названии бинарного пакета:
      %package -n libfoo%abiversion
      и в секции %files:
      %_libdir/lib%name.so.%abiversion
      (последнее — для подстраховки от случайной смены soname при обновлении пакета).
    2. Название пакета libfoo-devel оставляем неизменным
  3. Если в новом пакете libfooM будут пересечения по файлам со старым пакетом libfoo (например, был упакован файл /usr/bin/foo, который переехал в libfooM), проставляем у libfooM конфликт со старой версией:
    Conflicts: libfoo < 1.1.28-alt4
    (если пересечение есть и с собранным из libfooN пакетом, указываем <= в Conflicts, но такую ситуацию желательно не допускать)

Добавление пакета libfooN

  1. Делаем копию пакета libfoo из репозитория (то есть старого) под названием libfooN.
  2. Отключаем в пакете сборку всего, что может конфликтовать по файлам с пакетами новой версии, ведь у нас цель обеспечить возможность одновременной установки libfooN и libfooM.
  3. Оставляем только подпакет libfoo (единственный, который будет формироваться при сборке).
  4. Для указания версии библиотеки добавляем в спек
    %define abiversion N
    и используем его в секции %files -n libfoo:
    %_libdir/lib%name.so.%abiversion
    (для подстраховки от случайной смены soname при обновлении пакета).
  5. Указываем Legacy группу для пакета:
    Group: System/Legacy libraries

Дополнительные пункты для самопроверки

  1. При взгляде на исходные пакеты: добавляется новый пакет libfooN (из него собирается бинарный libfoo[1]).
  2. При взгляде на бинарные пакеты: добавляется новый пакет libfooM (из него собирается бинарный libfooM и libfoo-devel)
  3. Если библиотека пакуется под SharedLibsPolicy, то в пакете с библиотекой не должно быть ничего, что может потом в дальнейшем начать конфликтовать с файлами из нового пакета этой библиотеки. То есть содержимое /usr/bin должно оказаться в %name-tools, а %_datadir/%name/ — в %name-common (условно).
  4. Следует придерживаться того правила, чтобы пакет с библиотекой не менял имя, поскольку существует вероятность[2] того, что apt не сможет корректно обработать ситуацию, когда библиотека с конкретным soname переезжает в пакет с другим названием.
  5. При переходе на SharedLibsPolicy следует исправить все недостатки разбиения по подпакетам — смена soname удобный момент для этого.
  6. Добавлять в libfooM провайд libfoo = %version-%release не следует, поскольку для зависимостей между пакетами это только внесёт путаницу, а вручную обычно библиотеки не устанавливают (в отличие от devel-пакетов).


Причины для применения Shared Libs Policy

  • Постепенная пересборка пакетов в репозитории при обновлении пакета.
    Чтобы не общаться с другим мантейнерами на предмет разрешения пересборки их пакетов в вашем большом задании, вы по сути просто собираете новую библиотеку в новый пакет, не нарушая целостность репозитория, а мантейнерам оставляете возможность чинить их пакеты, если они перестают собираться с новой версии библиотеки.
  • Необходимость одновременного существования разных версий библиотек в репозитории.
    Библиотека может быть очень известной (например, libpng) и сторонние бинарные программы могут быть привязаны к определённой версии библиотеки, не той,которая основная в репозитории.
  • При проблемах обновления с бранча на бранч возможность точечных обновлений чрезвычайно расширяется, т.к. старые библиотеки со старыми SONAME вытеснять никто не будет. Например, возможность обновить один новый пакет foo , зависящий от libname2 не затронет другой старый пакет bar, который зависит от старой версии libname1, которой уже нет в новом репозитории, но еще есть в системе. Если бы пакет со старой и новой версией библиотеки назывался libname, то по цепочке потянулась бы вся борода из других библиотек и пакетов, наткнувшись на какую-нибудь другую проблему обновления.

Причины для неприменения Shared Libs Policy

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


Вынесение утилит в подпакет

Исходя из правила «в пакете с библиотекой не должно быть ничего, что может потом в дальнейшем начать конфликтовать с файлами из нового пакета этой библиотеки», утилиты и прочие неверсионированные файлы (т.е. скорее всего все, кроме собственно библиотеки) должны упаковываться в отдельный подпакет.

К примеру, от пакета libfooM ожидается собственно библиотека, а /usr/bin/foo должен быть упакован в отдельный подпакет, например libfoo-utils или просто foo, в зависимости от важности команды и их количества.

Такой пакет скорее всего будет иметь зависимость на libfoo, но пакет libfoo не должен зависеть от утилит (если библиотека вызывает утилиты, тогда разделение на подпакет не имеет смысла).

Польза от вынесения утилит в подпакет

  • Чтобы не было файлового конфликта у любых релизов libfoo, libfooN, libfooM.
  • Чтобы тот, кто устанавливал /usr/bin/foo, не потерял его в системе, когда /usr/bin/foo переедет из пакета libfoo в libfooM.
  • Минимизация зависимостей пакета с библиотекой. Если /usr/bin/foo это скрипт на python, то в итоге у пакета с библиотекой раздуются зависимости.

Благодарности

За появление этой статьи большая благодарность Глебу, начавшему обсуждение[3] и другим участникам:

  • Gleb Fotengauer-Malinovskiy
  • Mikhail Tergoev
  • Alexey V. Vissarionov
  • Sergey V Turchin
  • Anton Farygin

Ссылки

  1. libfoo, а не libfoo1, чтобы соблюсти условие о том, что библиотека не должна переезжать в пакет с другим названием.
  2. glebfm@: Я (как автор того изменения в apt, которое улучшило положение дел) всегда был уверен, что просто сильно уменьшилась вероятность. https://bugzilla.altlinux.org/show_bug.cgi?id=46837#c11
  3. https://lore.altlinux.org/devel/ZL7b3jkMiopSSuVX@glebfm.altlinux.org/

См. также