Что такое *.so.*.* libs
Когда я делаю ls -l
в /usr/lib
Я вижу много людей с "sameName.so.*.*"
расширение.
- Каково значение этих расширений?
- Почему создаются мягкие ссылки? в чем их польза?
Один пример очень поможет в понимании.
2 ответа
Это трюк, используемый для управления версиями общих объектных файлов. Это способ избежать ужасного ада 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 общего объекта.
Фактические детали реализации могут несколько отличаться (я основываю свой ответ на более ранних версиях UNIX, и 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
во время выполнения из-за SONAME. Затем вы обновляетесь до исправленной, но бинарно-совместимой 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
и не нуждается в обновлении.