Почему при загрузке файла SO он добавляет версию до конца?

Я использую CMake и Ninja для создания тестового исполняемого файла, написанного на C ++. Я использую gcc 4.8. Я на Ubuntu 14.

Я запускаю CMake для настройки скриптов сборки ninja, затем я запускаю ninja для сборки. Я указываю libcrypto.so и другие файлы openssl *.so качестве целевых зависимостей в сценарии CMake.

При запуске исполняемого файла возникает следующая ошибка:

ошибка при загрузке разделяемых библиотек: libcrypto.so.1.0.0: невозможно открыть файл общих объектов: нет такого файла или каталога

У меня есть файл libcrypto.so который находится рядом с тестовым исполняемым файлом:

 -rw-r--r-- 1 robert domain users 1796847 Apr 20 15:43 libboost_wave.so -rw-r--r-- 1 robert domain users 410916 Apr 20 15:43 libboost_wserialization.so -rw-r--r-- 1 robert domain users 2251519 Apr 21 11:28 libcrypto.so -rw-r--r-- 1 robert domain users 701627 Apr 20 15:43 libEGL.so -rw-r--r-- 1 robert domain users 4255871 Apr 20 15:43 libGLES_CM.so -rw-r--r-- 1 robert domain users 7550551 Apr 20 15:43 libGLESv2.so -rw-r--r-- 1 robert domain users 949113 Apr 17 14:34 libsqlite.so -rw-r--r-- 1 robert domain users 496298 Apr 21 11:28 libssl.so -rwxr-xr-x 1 robert domain users 3099250 Apr 21 11:30 Test_UI_String* 

(Исполняемый файл, который я запускаю, называется Test_UI_String )

CMake настроен для вывода разделяемых библиотек рядом с исполняемыми файлами, потому что на других платформах, таких как Windows (где я больше всего знаком с разработкой), DLL-файлы должны быть рядом с EXE для его поиска и загрузки.

Я смущен тем, почему он добавил 1.0.0 в конец файла библиотеки. Он должен искать его без номера версии в конце, поскольку, когда я связал зависимость, у него было то же имя, что и libcrypto.so , теперь в каталоге, показанном выше.

Я хотел бы лучше понять поведение здесь, однако мой основной вопрос в основном заключается в том, как заставить это работать по назначению (найдите зависимости библиотеки, которые находятся в том же каталоге, что и исполняемый файл).

Когда компоновщик генерирует исполняемый файл (или другую разделяемую библиотеку), он ищет библиотеки, запрошенные с использованием -l путем префикса lib и суффикса. Кроме имени. Например, если вы запрашиваете -lcrypto тогда он ищет libcrypto.so .

После того, как библиотека была найдена, компоновщик читает фрагмент метаданных из библиотеки, называемой ее soname. Затем соната записывается в исполняемый файл, и это имя будет использоваться для повторного поиска той же библиотеки во время выполнения. Соната может, конечно, отличаться от имени, под которым библиотека была фактически найдена во время ссылки.

Вариант использования этой функции – возможность одновременного использования нескольких разных, несовместимых версий библиотеки, установленной в системе. Вот как это обычно используется.

Во-первых, позвольте мне описать, что произойдет в отсутствие этого соглашения:

Заголовки разработки (файлы .h ) связаны с конкретной версией библиотеки, а файл .so содержит эту версию:

 /usr/include/mylibrary.h /usr/lib/libmylibrary.so 

Приложение myapp было скомпилировано против этой версии библиотеки и загружает /usr/lib/libmylibrary.so во время выполнения.

Позже библиотека обновляется до новой версии. Оба .h и .so файла заменяются новой версией. К сожалению, новая версия имеет несовместимый ABI.

Теперь, когда выполняется myapp , он выдает или демонстрирует неопределенное поведение, потому что он был скомпилирован с одной версией с одним ABI, но при загрузке другой версии во время выполнения.

Что происходит с соглашением о сонате:

Библиотека устанавливается следующим образом:

 /usr/include/mylibrary.h /usr/lib/libmylibrary.so -> libmylibrary.so.1 /usr/lib/libmylibrary.so.1 

И /usr/lib/libmylibrary.so.1 встроил в нее сонавную libmylibrary.so.1 .

Когда myapp построен, он находит /usr/lib/libmylibrary.so но компоновщик следует символической ссылке и фактически загружает /usr/lib/libmylibrary.so.1 . Кроме того, soname libmylibrary.so.1 – это то, что фактически записывается внутри myapp . Во время выполнения myapp напрямую загружает /usr/lib/libmylibrary.so.1 , минуя символическую ссылку.

Позже библиотека обновляется до новой версии с несовместимым ABI. Оба .h и .so файла заменяются новой версией. libmylibrary.so.2 новый файл libmylibrary.so.2 . libmylibrary.so.1 из старой версии остается в покое.

 /usr/include/mylibrary.h /usr/lib/libmylibrary.so -> libmylibrary.so.2 /usr/lib/libmylibrary.so.1 /usr/lib/libmylibrary.so.2 

Теперь, когда выполняется myapp , продолжается загрузка libmylibrary.so.1 и все еще функционирует как ожидалось. Но если будут установлены другие новые приложения или перекомпилирована сама myapp , будет использоваться символьная ссылка и будет использоваться новая версия.


Проблема, которую вы видите, заключается в том, что когда ваше приложение было связано, компоновщик обнаружил библиотеку со своим именем libcrypto.so.1.0.0 внутри нее.

Была ли ваша копия libcrypto.so сгенерирована с помощью soname, если libcrypto.so.1.0.0 ?

Другая возможность, вполне вероятно, заключается в том, что ваша копия libcrypto.so не имеет в ней имени, но компоновщик действительно нашел и использовал системную версию libcrypto.so (из OpenSSL), и именно там он получил сонат.