3

我有很多静态库。一个是 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 的对象。这行代码将进行向下转换。

为了隐藏dynamic_lib.so中static_lib_a.a的所有符号,我使用-fvisibility=hidden来构建这个静态库。我发现如果我添加 - fvisibility=hidden, pElementNode 将在运行时返回一个 NULL 指针。

gcc 编译器的版本是 3.4.4。

以前有没有人有类似的问题?

4

3 回答 3

3

您的问题的根源在gcc wiki的“C++ 异常问题”部分下进行了描述。确保您遵循那里的“模糊链接”链接并阅读有关虚拟表和类型信息的部分。

这一切都适用于您的情况,因为这些类xerces::DOMNodexerces::DOMElement包含非纯非内联虚函数(实际上这些类完全包含在标题中)。这意味着任一类的虚拟表都会在包含其标题的每个目标文件中发出。

dynamic_cast 正常工作所需的任一类的类型信息符号在与虚拟表相同的对象中发出,即在包含其标题的每个对象文件中发出。

当您将库标记为隐藏可见性时,static_lib_a.a中的对象xerces::DOMNodexerces::DOMElement对象中的所有类型信息符号都被标记为隐藏。正如 wiki 页面指出的那样,这确保了链接器随后会将其标记为隐藏在 dynamic_lib.so 中,并且您的 dynamic_cast 将失败。

于 2011-05-13T23:28:21.403 回答
1

使用隐藏可见性是确保您的图书馆仅通过指定的访问点使用的好方法。如果您修改它,这是一个巨大的优势,因为您确切地知道您的库是如何在外部使用的,因此您可能会破坏的限制。

这是一种与 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;

于 2011-02-25T11:59:06.747 回答
0

dynamic_cast要求派生类的 typeinfo节点指向基类的 typeinfo 节点,这是通过动态重定位完成的。如果 typeinfo 节点的符号不可见,则包含派生类节点的模块将拥有自己的副本,然后 dynamic_cast 假定这些类来自不同的树并且不允许强制转换。

您需要向基类定义添加一个声明默认可见性的属性。

于 2011-02-25T12:21:39.670 回答