Это трюк, используемый для управления версиями общих объектных файлов. Это способ избежать страшного ада 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
, получат определенную младшую версию определенной основной версии.