Как работают числа SO (общего объекта)?

Как работают числа SO (общего объекта)?

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

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

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

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

решение1

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

решение2

Номера в общих библиотеках — это соглашение, используемое в Linux для идентификации API библиотеки. Обычно формат следующий:

libFOO.so.MAJOR.MINOR

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

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

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

решение3

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

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и использовать их разными приложениями одновременно.

решение4

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

Связанный контент