Сбой dynamic_cast при скрытии символа - PullRequest
3 голосов
/ 25 февраля 2011

У меня много статических библиотек.Одним из них является static_lib_a.a.Я создаю динамическую библиотеку dynamic_lib.so, чтобы собрать их вместе.

В static_lib_a.a он использует xerces 3.1.1 для анализа xml.Ниже приведен фрагмент кода в static_lib_a.a

xerces::DOMElement *pElementNode = dynamic_cast<xerces::DOMElement *>(pNode);

Тип pNode: xerces :: DOMNode.Он присваивается объекту xerces :: DOMElement.Эта строка кода будет делать downcasting.

Чтобы скрыть все символы static_lib_a.a в dynamic_lib.so, я использую -fvisibility = hidden для создания этой статической библиотеки.Я обнаружил, что если я добавлю - fvisibility = hidden , pElementNode вернет нулевой указатель во время выполнения.

Версия компилятора gcc - 3.4.4.

У кого-нибудь раньше были подобные проблемы?

Ответы [ 3 ]

3 голосов
/ 14 мая 2011

Корень вашей проблемы описан в gcc wiki в разделе, озаглавленном «Проблемы с исключениями C ++».Убедитесь, что вы переходите по ссылке "неопределенная связь" и читаете разделы о виртуальных таблицах и typeinfo.

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

Символы typeinfo для любого класса, которые необходимы для правильной работы dynamic_cast, генерируются в том же объекте, что ивиртуальная таблица, т. е. в каждом объектном файле, который включает его заголовок.

Когда вы пометили свою библиотеку скрытой видимостью, все символы typeinfo для xerces::DOMNode и xerces::DOMElement в объектах из static_lib_a.a были отмечены как скрытые.Как указывает вики-страница, это гарантирует, что компоновщик пометит его как скрытый в dynamic_lib.so, и ваш dynamic_cast потерпит неудачу.

1 голос
/ 25 февраля 2011

Использование скрытой видимости - отличный способ убедиться, что ваша библиотека используется только через указанные точки доступа.Это огромное преимущество, если вы когда-нибудь измените его, так как вы точно знаете, как ваша библиотека используется снаружи, и, следовательно, ограничение того, что вы можете потенциально сломать.

Это очень похожая техника на Windows, которая заставляет вас declspecчто является частью доступной части DLL, за исключением небольшой разницы, которую вы не указываете при импорте или экспорте, и поэтому ваша библиотека может создавать «видимые» функции, которые она использует, а не реализует.

Чтобы ответить на ваш вопрос, я думаю, что видимость поддерживается только в версии 4 и выше.Конечно, мы используем его здесь с этим

#if defined(__GNUC__) && __GNUC__ >= 4

Когда вы используете скрытую видимость, вам необходимо четко указать, какие символы вы хотите видеть.Таким образом, у вас есть это:

__attribute__((visibility("default")))

, который вы, вероятно, #define, чтобы быть чем-то более читабельным, может быть, SO_EXPORT, таким образом:

#define SO_EXPORT __attribute__((visibility("default")))

Определить классы:

class SO_EXPORT MyAccessInterface;

и методы что-то вроде:

SO_EXPORT int doSomething( parameters );

На самом деле у нас также есть подобные макросы для скрытой видимости(как указано выше, но с «скрытым» вместо «по умолчанию»).Таким образом, даже когда мы используем видимость «по умолчанию» для всего проекта, мы можем скрыть некоторые детали реализации.

#define SO_HIDDEN __attribute__((visibility("hidden")))

class SO_HIDDEN MyClassImpl;

0 голосов
/ 25 февраля 2011

dynamic_cast требует, чтобы узел typeinfo для производного класса указывал на узел typeinfo для базового класса, что делается с помощью динамического перемещения.Если символ для узла typeinfo не виден, то модуль, содержащий узел для производного класса, будет иметь свою собственную копию, и dynamic_cast тогда предполагает, что эти классы принадлежат разным деревьям, и запрещает приведение.

Вынеобходимо добавить атрибут, объявляющий видимость по умолчанию, к определению базового класса.

...