Связывание двух общих библиотек с одними и теми же символами - PullRequest
44 голосов
/ 30 июня 2011

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

Например, обе библиотеки определяют глобальную функцию bar(), которую каждая вызывает внутри. Библиотека 1 вызывает его из foo1(), а библиотека 2 вызывает его из foo2().

Lib1.so:

T bar
T foo1()     // calls bar()

Lib2.so:

T bar
T foo2()     // calls bar()

Если я связываю свое приложение с Lib1.so, а затем с Lib2.so, вызывается реализация bar из Lib1.so даже при вызове foo2(). С другой стороны, если я связываю свое приложение с Lib2.so, а затем с Lib1.so, то бар всегда вызывается из Lib2.so.

Есть ли способ заставить библиотеку всегда предпочитать ее собственную реализацию над любой другой библиотекой?

Ответы [ 3 ]

45 голосов
/ 30 июня 2011

Есть несколько способов решить эту проблему:

  • Передайте -Bsymbolic или -Bsymbolic-functions компоновщику. Это имеет глобальный эффект: каждая ссылка на глобальный символ (типа функции для -Bsymbolic-functions), который может быть преобразован в символ в библиотеке, преобразуется в этот символ. При этом вы теряете возможность вставлять внутренние библиотечные вызовы в эти символы, используя LD_PRELOAD. Символы по-прежнему экспортируются , поэтому на них можно ссылаться извне библиотеки.

  • Используйте версию сценария , чтобы пометить символы как локальные для библиотеки, например, используйте что-то вроде: {local: bar;}; и передайте --version-script=versionfile компоновщику. Символы не экспортируются.

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

Вы можете проверить, какие символы экспортируются с помощью objdump -T.

3 голосов
/ 30 июня 2011

Вам нужно будет создать две общие библиотеки-оболочки, по одной для каждой из ваших существующих библиотек.Каждый из них должен быть построен с --dynamic-list, который перечисляет только несколько неконфликтующих символов, которые определяют API.Вам также понадобится -Bsymbolic, чтобы избежать какой-либо глобальной комбинации.

Возможно, вам будет проще получить доступ к полученным библиотекам через dlopen с подходящими опциями.

1 голос
/ 20 февраля 2018

Другим способом решения этой проблемы является использование макроса для изменения пространства имен.

Предварительные условия

  • Все элементы (функции, классы, глобальные переменные, ...) находятся в пространстве имен.
  • Библиотека не сильно зависит от макросов в заголовках.

Решение

  • При компиляции библиотеки определите макрос с именем пространства имен, чтобы определить его для чего-то другого.Например, если пространством имен является LibNS, используйте -DLibNS=LibNSv1 для одного случая и -DLibNS=LibNSv2 для другого.
  • При использовании библиотек в коде определите макрос в соответствии с текущей ситуацией;

    #define LibNS LibNSv1
    #include "my_lib.h"
    #undef LibNS
    

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

  • Когда проблемная библиотека используется (хотя бы частично) в заголовочных файлах (дляпримеры шаблонов, inline, ...);когда вы включаете их в код вашего исполняемого файла, resolver не имеет представления, должны ли эти функции вызываться из Lib1.so или Lib2.so.
  • Ваш компилятор плохо поддерживает другие решения (не долженслучается с нашими 32/64-битными процессорами Intel / AMD, но из поиска Google кажется, что некоторые другие платформы могут иметь проблемы).

Потенциальные проблемы

  • Может быть проблематично использовать обе версии в одном файле cpp вашего исполняемого файла;#include "my_lib.h", вероятно, использует макрос для защиты от множественного включения, а отмена их определения во избежание этого может привести к множеству различных проблем (автор библиотеки может изменить имя макроса в будущем, заголовок определяет некоторые другие макросы и т. Д.).
  • Имя LibNS может использоваться для чего-то еще в библиотеке (переменная, функция и т. Д.);в этом случае это имя также будет изменено на LibNSv1 или LibNSv2.Это может привести к другим проблемам в зависимости от библиотеки и способа ее использования.

Примечания

  • Это не предназначено для замены принятого в настоящее время ответа(от ninjalj; не стесняйтесь копировать-вставить его), но расширьте его другим подходом.
  • Основная причина, по которой я разместил этот ответ, заключается в том, что я столкнулся с этой проблемой сегодня, но ответ не помог из-за проблемныхкод находится в заголовочных файлах.
  • Мой источник: https://spin.atomicobject.com/2014/06/03/static-linking-c-plus-plus/
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...