Как работают номера SO (общий объект)?

124

Я знаю, что общие объекты в Linux используют «так числа», а именно, что разные версии общего объекта имеют разные расширения, например:

  • example.so.1
  • example.so.2

Я понимаю, что идея состоит в том, чтобы иметь два разных файла, чтобы в системе могли существовать две версии библиотеки (в отличие от «DLL Hell» в Windows). Я хотел бы знать, как это работает на практике? Часто я вижу , что example.soэто на самом деле является символической ссылкой на example.so.2где .2это последняя версия. Как тогда приложение в зависимости от более старой версии example.soидентифицирует его правильно? Есть ли какие-либо правила относительно того, какие числа нужно использовать? Или это просто соглашение? Является ли это случаем, что, в отличие от Windows, где двоичные файлы программного обеспечения передаются между системами, если в системе установлена ​​более новая версия общего объекта, она автоматически связывается со старой версией при компиляции из исходного кода?

Я подозреваю, что это связано с, ldconfigно я не уверен, как.

tshepang
источник

Ответы:

88

Сами двоичные файлы знают, от какой версии разделяемой библиотеки они зависят, и запрашивают ее специально. Вы можете использовать, lddчтобы показать зависимости; мои для lsявляются:

$ ldd /bin/ls
    linux-gate.so.1 =>  (0xb784e000)
    librt.so.1 => /lib/librt.so.1 (0xb782c000)
    libacl.so.1 => /lib/libacl.so.1 (0xb7824000)
    libc.so.6 => /lib/libc.so.6 (0xb76dc000)
    libpthread.so.0 => /lib/libpthread.so.0 (0xb76c3000)
    /lib/ld-linux.so.2 (0xb784f000)
    libattr.so.1 => /lib/libattr.so.1 (0xb76bd000)

Как видите, это указывает, например libpthread.so.0, не просто libpthread.so.


Причина символической ссылки - для компоновщика. Когда вы хотите связать libpthread.soнапрямую, вы указываете gccфлаг -lpthread, и он автоматически добавляет libпрефикс и .soсуффикс. Вы не можете сказать, чтобы он добавлял .so.0суффикс, поэтому символическая ссылка указывает на новейшую версию библиотеки, чтобы облегчить

Майкл Mrozek
источник
Знак равенства "= ls" не должен присутствовать. Просто используйте «ldd ls»
bmacnaughton
1
@bmacnaughton Это, вероятно, даст вам ошибку, поскольку lddтребует полного пути к исполняемому файлу. =lsделает это в zsh, но я изменил его, так как не все используют эту оболочку
Майкл
Интересно. Я использую bash на Ubuntu, и он работает без полного пути. Спасибо за объяснение - я не использую Zsh.
bmacnaughton
60

Числа в общих библиотеках являются условным обозначением, используемым в Linux для определения API библиотеки. Обычно формат таков:

libFOO.so.MAJOR.MINOR

И, как вы заметили, обычно есть символическая ссылка от libFOO.so к libFOO.so.MAJOR.MINOR. ldconfig отвечает за обновление этой ссылки до последней версии.

Значение MAJOR обычно увеличивается при изменении API (удаляются новые точки входа или изменяются параметры или типы). MINOR обычно увеличивается для выпусков исправлений ошибок или когда новые API вводятся без нарушения существующих API.

Более подробное обсуждение можно найти здесь: Разделение разделяемых библиотек

miguel.de.icaza
источник
Привет Мигель, спасибо за это, позор, я не могу принять два ответа, потому что это прекрасно дополняет вышесказанное. +1 от меня, отличная ссылка тоже, еще раз спасибо!
4
Это почти правильно, но это действительно libFOO.so.MAJOR.MINOR(так что не в конце)
JonnyJD
6
Этот ответ так неверен . Во-первых, числа, которые вы видите, не имеют ничего общего с API, это чисто ABI. Во-вторых, соглашение здесь не является семантическим версионированием ВСЕ, как вы предлагаете ответить. Скорее всего, это Libtool конвенция , которая имеет хорошее свойство отображения в одной библиотеке номер версии , который ld.so можно сравнить (см gnu.org/software/libtool/manual/html_node/... для получения дополнительной информации)
NewbiZ
23

Разделяемые библиотеки должны иметь версии по следующей схеме:

blah.so.X.Y.Z

где

  • X = обратно несовместимый выпуск ABI
  • Y = обратно совместимый выпуск ABI
  • Z = только внутренние изменения - без изменений в ABI

Как правило, вы видите только первую цифру, hello.so.1потому что первая цифра - это единственное, что нужно для идентификации «версии» библиотеки, поскольку все остальные цифры обратно совместимы.

ldconfigведет таблицу того, какие общие библиотеки доступны в системе и где существует путь к этой библиотеке. Вы можете проверить это, запустив:

ldconfig -p

Когда пакет создается для чего-то вроде Red Hat, общие библиотеки, вызываемые в двоичном файле, будут просматриваться и добавляться как зависимости пакета во время сборки RPM. Поэтому при переходе к установке пакета установщик проверит hello.so.1, установлен ли он в системе, путем проверки ldconfig.

Вы можете увидеть зависимости пакета, выполнив что-то вроде:

rpm -qpR hello.rpm

Эта система (в отличие от Windows) позволяет hello.soустанавливать в системе несколько версий и использовать их одновременно различными приложениями.

ascotan
источник
Я думаю, что это лучший ответ.
Кемин Чжоу
1
Совместно используемые библиотеки должны иметь версию согласно следующей схеме (…). Не могли бы вы предоставить ссылку на это утверждение?
Петр Доброгост
19

libNAME.so - это имя файла, используемое компилятором / компоновщиком при первом поиске библиотеки, указанной в -lNAME. Внутри файла общей библиотеки находится поле под названием SONAME. Это поле устанавливается, когда сама библиотека сначала связывается в общий объект (так) в процессе сборки. Этот SONAME - это то, что компоновщик хранит в исполняемом файле, в зависимости от того, с каким общим объектом он связан. Обычно SONAME имеет вид libNAME.so.MAJOR и изменяется каждый раз, когда библиотека становится несовместимой с существующими исполняемыми файлами, связанными с ней, и обе основные версии библиотеки могут быть установлены по мере необходимости (хотя для разработки будет указана только одна). as libNAME.so) Кроме того, для поддержки простого обновления между второстепенными версиями библиотеки libNAME.so.MAJOR обычно представляет собой ссылку на файл, подобный libNAME.so.MAJOR.MINOR. Можно установить новую минорную версию, и после ее завершения ссылка на старую минорную версию будет увеличена, чтобы указать на новую минорную версию, немедленно обновляющую все новые исполнения для использования обновленной библиотеки. Также смотрите мой ответ наLinux, GNU GCC, ld, версии скриптов и двоичный формат ELF - Как это работает?

penguin359
источник