Product SiteDocumentation Site

12.2. Версионирование

Подробнее рассмотрим получившуюся библиотеку для обсуждения версионирования:
@user
[user@VM inc-pkg]$ ls -la .libs/*.so*
lrwxrwxrwx 1 user user    15 авг  4 16:08 .libs/libinc.so -> libinc.so.0.0.0
lrwxrwxrwx 1 user user    15 авг  4 16:08 .libs/libinc.so.0 -> libinc.so.0.0.0
-rwxr-xr-x 1 user user 15416 авг  4 16:08 .libs/libinc.so.0.0.0
[user@VM inc-pkg]$
При работе с библиотеками (и, в целом, любыми объектами, требующими явный параметр для отслеживания изменений и совместимости) принято использовать специальные правила версионирования.
Во-первых, это формат хранения библиотек в виде одного файла с сопутствующими символьными ссылками. Бесчисловая версия используется для создания зависимостей на библиотеку при сборке (если не требуется строгая зависимость на конкретную версию), мажорная («основная», с одним числом) используется для указания на основную поддерживаемую версию, а последняя (единственная реальная библиотека) является самим рабочим объектом.
Во-вторых, это параметры, по которым ведётся отслеживание изменений, и правила версионирования. В случае с библиотеками версионирование описывается через изменение ABI —  Application Binary Interface. Если API описывает, с какими параметрами следует вызывать функции библиотеки в исходных текстах программ, и какие значения они возвращают, то ABI отражает, во что именно эта договорённость превращается после компиляции. Таким образом, очень важно, чтобы исполняемый файл и разделяемая библиотека были совместимы по ABI: если такая совместимость есть, пускай даже при сборке программы использовалась библиотека слегка другой версии, программа будет работать штатно. Если совместимости нет, то лучшее, что может сделать библиотека — это немедленно завершить программу с ошибкой.
Повсеместно используемые большие библиотеки, например, GLibc, могут быть совместимы сразу с несколькими ABI, для более простых случаев libtool предлагает схему из трёх счётчиков —  current:revision:age:
  • current увеличивается при каждом изменении ABI —  это т. н. «номер интерфейса»;
  • revision увеличивается при каждом изменении в библиотеке, которое не отразилось на ABI (исправление ошибок, изменение функциональности и т. п.); если current увеличилось, revision обнуляется;
  • age изменяется вместе с current; он увеличивается при каждом обратно совместимом изменении (например, при добавлении новой функции или при изменении, не затрагивающем ABI), а в противном случае — обнуляется.
Таким образом, libtool versioning решает сразу три задачи:
  1. При любом изменении версия увеличивается;
  2. При изменении ABI версия увеличивается настолько, что становится больше любых версий, в которых ABI не поменялось;
  3. По версии можно узнать диапазон предоставляемых «номеров интерфейса», с которыми гарантирована обратная совместимость —  это диапазон от current до current —  age.
При более простом семантическом версионировании описание ведётся значениями MAJOR.MINOR.PATCH и меняется по следующим правилам:
  • обратно несовместимые изменения ABI (удаление / изменение) — MAJOR++.MINOR=0.PATCH=0;
  • обратно совместимые изменения ABI (добавление) —  MAJOR.MINOR++.PATCH=0;
  • обратно совместимые исправления ABI и изменения, не затрагивающие ABI — MAJOR.MINOR.PATCH++.