%3F.png)
Я знаю, что общие объекты в 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 — как это работает?