Вопрос
Когда я делаю ls -l
в /usr/lib
Я вижу много либеров с "sameName.so.*.*"
расширение.
- Каково значение этих расширений?
- Почему созданы мягкие ссылки? Что они используют?
Один пример очень поможет в понимании.
Решение
Это трюк, используемый для версий общих объектных файлов. Это способ избежать страшного ада DLL, который возник из -за ленивого связывания.
Преимущество ленивого связывания (или позднего привязки) состоит в том, что компоненты вашего исполняемого файла могут быть изменены без фактической связи этих исполняемых файлов. Это позволяет исправлять ошибки в сторонних компонентах без необходимости отправлять новый исполняемый файл, среди прочего.
Недостаток точно такой же, как и преимущество. Ваш исполняемый файл может обнаружить, что предположения, которые он сделал о базовых библиотеках, были изменены, и это, вероятно, вызовет всевозможные проблемы.
Версия общих объектов - это один из способов избежать этого. Другой был бы нет Поделитесь объектами вообще, но у них также есть плюсы и минусы, которые я не буду здесь вовлекать.
Например, допустим, у вас есть версия 1 xyz.so
. Анкет У вас есть файл и символическая ссылка на этот файл:
pax> ls -al xyz*
-rw-r--r-- 1 pax paxgroup 12345 Nov 18 2009 xyz.so.1
lrwxrwxrwx 1 pax paxgroup 0 Nov 18 2009 xyz.so -> xyz.so.1
Теперь, когда вы создаете исполняемый файл exe1
, связывая это с xyz.so
, он будет следить за символической ссылкой, чтобы хранить xyz.so.1
в исполняемом файле как то, что нужно загружать во время выполнения.
Таким образом, когда вы обновляете общую библиотеку таким образом:
pax> ls -al xyz*
-rw-r--r-- 1 pax paxgroup 12345 Nov 18 2009 xyz.so.1
-rw-r--r-- 1 pax paxgroup 67890 Nov 18 2009 xyz.so.2
lrwxrwxrwx 1 pax paxgroup 0 Nov 18 2009 xyz.so -> xyz.so.2
Ваш первоначальный исполняемый файл exe1
будем Все еще Загрузить версию 1 общего объекта.
Однако любые исполняемые файлы, которые вы создаете сейчас (например, exe2
) будет связан с версией 2 общего объекта.
Фактические детали реализации могут несколько варьироваться (я основываю свой ответ на более ранних Unixes, и Linux, кажется, делает версию немного более интеллектуально, чем просто следуя символическим ссылкам). У IBM DeveloperWorks есть хорошая статья о том, как это сделано здесь.
Когда вы создаете общий объект, вы даете ему как настоящее имя, так и настоящее имя soname
. Анкет Они используются для установки общего объекта (который создает как объект, так и ссылку на него).
Таким образом, вы можете получить ситуацию:
pax> ls -al xyz*
-rw-r--r-- 1 pax paxgroup 12345 Nov 18 2009 xyz.so.1.5
lrwxrwxrwx 1 pax paxgroup 0 Nov 18 2009 xyz.so.1 -> xyz.so.1.5
lrwxrwxrwx 1 pax paxgroup 0 Nov 18 2009 xyz.so -> xyz.so.1
с xyz.so.1.5
обладая SONAME
из xyz.so.1
.
Когда линкер ссылается в xyz.so
, он следует по ссылкам вплоть до xyz.so.1.5
и использует свой SONAME
из xyz.so.1
хранить в исполняемом файле. Затем, когда ты бежать исполняемый файл пытается загрузить xyz.so.1
что укажет на конкретный xyz.so.1.N
(не обязательно версия 1.5).
Так что вы можете установить xyz.so.1.6
и обновить xyz.so.1
Ссылка на то, чтобы указать на него вместо этого, и уже будут выполнены исполняемые файлы вместо этого.
Одним из преимуществ этого многослойного метода является то, что вы можете иметь несколько потенциально несовместимые библиотеки с одинаковыми названиями (xyz.so.1.*
, xyz.so.2.*
) Но в каждой крупной версии вы можете свободно обновить их так как они должны быть совместимыми.
Когда вы ссылаетесь на новые исполняемые файлы:
- Те, кто связывается с
xyz.so
Получит последнюю незначительную версию последней крупной версии. - Другие, связывающие с
xyz.so.1
Получит последнюю незначительную версию конкретной крупной версии. - Третьи, связывающие с
xyz.so.1.2
Получит конкретную небольшую версию конкретной крупной версии.
Другие советы
Это Схема управления версиями для общих библиотек. Анкет У каждой библиотеки должно быть 3 имена:
- Настоящее имя: Фактическое название библиотеки,
libfoo.so.1.2.3
- "Soname": Имя записано в исполняемом файле, и ищет динамический линкер, ищет,
libfoo.so.1.2
. Анкет Это имя фактически написано внутри самого библиотеки и будет записано в исполняемом файле во время ссылки. Обычно это символизирует настоящее имя библиотеки (обычно последняя версия). - Имя линкера: Имя, которое вы даете линкеру при создании своей программы. Обычно ссылки на последнее Soname.
Пример
Скажи, что у тебя есть libfoo
Версия 1 установлена: libfoo.so
-> libfoo.so.1.0
-> libfoo.so.1.0.0
. Анкет Вы строите свою программу bar
с -lfoo
. Анкет теперь ссылается на libfoo
и загрузит libfoo.so.1.0
во время выполнения из -за Сонаме. Затем вы обновляетесь до исправленного, но совместимых с бинарной libfoo.so.1.0.1
заменив настоящий бинарный. bar
все еще ссылки на libfoo.so.1.0
и не нужно перестраивать.
Теперь представьте, что вы хотите построить новую программу baz
Это использует несовместимые изменения в Libfoo v1.1. Вы устанавливаете новую версию, а в вашей системе установлено две версии, установленные параллельно:
libfoo.so.1.0
->libfoo.so.1.0.1
libfoo.so
->libfoo.so.1.1
->libfoo.so.1.1.0
ПРИМЕЧАНИЕ Имя линкера было обновлено до последней версии (это версия, соответствующая заголовкам, которые вы установили в /usr/include
).
Вы строите baz
, и это связано с libfoo.so
и нагрузки libfoo.so.1.1
во время выполнения. Не это bar
все еще бежит против libfoo.so.1.0
и не нужно обновляться.