GCC ссылка на имя компоновщика общего объекта - PullRequest
7 голосов
/ 14 января 2011

Предположим, у меня есть:

  • /usr/lib/libsomething.so.1 на машине A;
  • /usr/lib/libsomething.so.2 на машине Б.

Обе машины имеют /usr/lib/libsomething.so символическую ссылку на свои соответствующие библиотеки.

Если я свяжусь, используя gcc с -lsomething (или даже /usr/lib/libsomething.so), он будет следовать по символической ссылке, а ldd на машине A выдаст что-то вроде:

libsomething.so.1 => /usr/lib/libsomething.so.1

Это означает, что она не сможет найти библиотеку на компьютере B.

Теперь я знаю, что это основные изменения номера версии, и я знаю, что они могут быть несовместимы, но я готов пойти на этот риск. Я хотел бы сказать компоновщику, что нужно искать libsomething.so и не переходить по символической ссылке, поэтому ldd покажет

libsomething.so => /usr/lib/libsomething.so.1

на А, но

libsomething.so => /usr/lib/libsomething.so.2

на B. И тогда загрузчик перейдет по символической ссылке на любую версию.

Кроме того, я не хочу отложенной загрузки с помощью dlopen или чего-либо еще. Я хочу, чтобы он связывался с общим объектом во время компиляции.

Возможно ли это вообще?

Ответы [ 2 ]

8 голосов
/ 12 марта 2013

Конечно, возможно создание исполняемого файла, использующего любую доступную версию разделяемой библиотеки.

Проблема заключалась в том, что вы связали свой исполняемый файл с soname (libsomething.so.1 и libsomething.so.2) для конкретной версии. Вы должны были сделать это с неверсированной soname libsomething.so.

Чтобы добиться этого, на машине для сборки вы должны скомпилировать и установить библиотеку с soname (ELF SONAME), равным libsomething.so (без версии), чтобы компоновщик мог выбрать это soname, пока создается исполняемый файл. *

В соответствии с HOWTO Shared Libraries , вы можете передать требуемую неверсированную soname при создании библиотеки:

gcc -shared -Wl,-soname,libsomething.so -o libsomething.so.X objectsomething.o

Затем, как только вы установите библиотеку и запустите ldconfig, вы получите:

  • символическая ссылка /lib/libsomething.so, указывающая на /lib/libsomething.so.1 на машине A;
  • символическая ссылка /lib/libsomething.so, указывающая на /lib/libsomething.so.2 на машине B.

Загрузчик (прогон ldd) будет выбирать неверсионные символические ссылки независимо от того, куда он указывает:

  • libsomething.so => /lib/libsomething.so (0xNNNNNNNN) на машине A;
  • libsomething.so => /lib/libsomething.so (0xNNNNNNNN) на машине B.

Динамический загрузчик Linux (ld.so) разрешает библиотеки на основе значения их сына, записанного в исполняемом файле (ELF NEEDED). Значение копируется из файла библиотеки (ELF SONAME) при сборке исполняемого файла. Пока в целевой системе есть символическая ссылка, совпадающая с именем, записанным в исполняемом файле, библиотека, указанная этой символической ссылкой, будет загружена.


Давайте пройдемся по вашей настройке и покажем команды для проверки предположений.

Я использовал Fedora 18 X86_64 для теста и настроил вывод на i686 для ясности.

  • Скомпилируйте libsomething.so.1 и libsomething.so.2. Убедитесь, что SONAME установлен в неверсированный libsomething.so:

    readelf -a libsomething.so.1 | grep SONAME
    0xNNNNNNNN (SONAME)             Library soname: [libsomething.so]
    
    readelf -a libsomething.so.2 | grep SONAME
    0xNNNNNNNN (SONAME)             Library soname: [libsomething.so]
    
  • Установите библиотеки на соответствующие компьютеры в каталоге /lib/. Запустите ldconfig -v на обеих машинах и проверьте вывод.

    ldconfig -v 2>&1 | grep something
    libsomething.so -> libsomething.so.1 (changed)
    
    ldconfig -v 2>&1 | grep something
    libsomething.so -> libsomething.so.2 (changed)
    
  • Скомпилируйте исполняемый файл и убедитесь, что он ссылается на одно и то же имя без версии в NEEDED.

    readelf -a executable | grep NEEDED
    0xNNNNNNNN (NEEDED)             Shared library: [libsomething.so]
    
  • Ваш исполняемый файл зависит от неверсированного libsomething.so сейчас. Скопируйте исполняемый файл на обе машины и запустите ldd для обеих копий.

    ldd executable
    libsomething.so => /lib/libsomething.so (0xNNNNNNNN)
    

    Последний вывод одинаков на обеих машинах, поскольку исполняемый файл был собран с soname без версии. Это заставляет загрузчик принимать неверсионные символические ссылки на целевые машины. И в зависимости от машины символическая ссылка может указывать на различную реализацию библиотеки libsomething.so.1 или libsomething.so.2.

2 голосов
/ 14 января 2011

Это означает, что она не сможет найти библиотеку на компьютере B.

И это все равно не предполагается.

По самому определению soversions , libsomething.so.2 означает, что API / ABI несовместим с libsomething.so.1.Поэтому просто добавление libsomething.so в таблицу библиотек программы для загрузки было бы фактически неверным.Символьная ссылка libsomething.so служит просто подсказкой ld, какую версию выбрать по умолчанию.

Из того, какой файл ld фактически открылся, для кодирования в программе потребуется поле DTNAME / SONAME.Если вы этого не хотите, не надевайте что-нибудь сонаму.Но это может легко стать болью ... начиная с появления недоступных символов при попытке запустить программу.

...