Одна и та же мажорная версия разделяемой библиотеки может состоять из нескольких файлов, отличающихся номерами минорных версий. Обычно имя soname указывает на последнюю минорную версию в рамках мажорной (как показано выше, в случае с libdemo.so). Это обеспечивает корректную семантику версионирования во время использования разделяемой библиотеки выполняющимися программами. На этапе статической компоновки копия имени soname (не зависящая от минорной версии) встраивается в исполняемый файл. Ее символьная ссылка впоследствии может быть перенаправлена на более новую (минорную) версию разделяемой библиотеки; благодаря этому исполняемый файл может загружать ее самую свежую версию. Кроме того, разные мажорные версии библиотеки имеют разные имена soname, что позволяет им благополучно сосуществовать и быть доступными для программ, которые в них нуждаются.
Помимо реального имени и soname, для каждой разделяемой библиотеки обычно определяется еще и третье имя,
Обычно компоновочное имя создается в том же каталоге, что и файл, на который оно ссылается. Оно может быть привязано к реальному имени или soname последней мажорной версии библиотеки. Привязка к soname, как правило, предпочтительней, так как изменения в одном имени автоматически отражаются в другом (в разделе 41.7 вы увидите, что программа ldconfig автоматизирует процедуру обновления soname, и это неявно сказывается и на компоновочном имени, если выбрать вышеописанный подход).
Если нужно скомпоновать программу с более старой мажорной версией библиотеки, то нельзя использовать компоновочное имя. Вместо этого на этапе компоновки следует указать подходящее реальное имя или soname.
Ниже показаны примеры некоторых компоновочных имен:
libdemo.so — > libdemo.so.2
libreadline.so — > libreadline.so.5
В табл. 41.1 собрана краткая информация о soname, реальном и компоновочном именах разделяемой библиотеки, а на рис. 41.3 показаны отношения между ними.
Таблица 41.1. Краткая информация об именах разделяемой библиотеки
Имя — Формат — Описание
Реальное имя — имя_библиотеки. so.мажорный_идентификатор. минорный_идентификатор — Файл, хранящий библиотечный код; один экземпляр на каждую мажорную-плюс-минорную версию библиотеки
Soname — имя_библиотеки. so.мажорный_идентификатор — Один экземпляр на каждую мажорную версию библиотеки; встраивается в исполняемый файл во время компоновки; используется на этапе выполнения для поиска библиотеки с помощью символьной ссылки с тем же именем, которое указывает на подходящее (самое свежее) реальное имя
Компоновочное имя — имя_библиотеки. so — Символьная ссылка на последнее реальное имя или (что более вероятно) на последнее имя soname; в единственном экземпляре; позволяет создавать команды компоновки, не зависящие от версии
Рис. 41.3.
Теперь, используя всю вышеприведенную информацию, мы покажем, как создать демонстрационную библиотеку, следуя общепринятым методикам. Для начала создадим объектные файлы:
$ gcc — g — c — fPIC — Wall mod1.c mod2.c mod3.c
Затем построим разделяемую библиотеку с реальным именем libdemo.so.1.0.1 и soname libdemo.so.1.
$ gcc — g — shared — Wl, — soname,libdemo.so.1 — o libdemo.so.1.0.1 \
mod1.o mod2.o mod3.o
Теперь можно создать символьные ссылки для soname и компоновочного имени:
$ ln — s libdemo.so.1.0.1 libdemo.so.1
$ ln — s libdemo.so.1 libdemo.so
Чтобы проверить результат, можно воспользоваться командой ls (с применением утилиты awk, которая отбирает только интересующие нас поля):
$ ls — l libdemo.so* | awk '{print $1, $9, $10, $11}'
lrwxrwxrwx libdemo.so — > libdemo.so.1
lrwxrwxrwx libdemo.so.1 — > libdemo.so.1.0.1
— rwxr-xr-x libdemo.so.1.0.1
Построим наш исполняемый файл, применяя компоновочное имя (обратите внимание: в команде компоновки не упоминаются номера версий), и запустим программу уже привычным нам способом:
$ gcc — g — Wall — o prog prog.c — L. -ldemo
$ LD_LIBRARY_PATH=. /prog
Called mod1-x1
Called mod2-x2