从另一个编译器导出的DLL加载类

时间:2014-06-30 17:09:48

标签: c++ class dll compiler-construction export

我必须向我的团队解释为什么从DLL导出类不是一个好的解决方案,如果我们计划使用来自不同编译器的DLL。但我无法找到证明。有没有东西像“编译器不应该提供向后兼容性,不同的编译器也可以实现自己的命名导出符号的样式,所以从DLL导出的类只能由同一个编译器使用”? 我知道这是真的,但我怎么能证明这一点?另外,如果你知道我的其他论据,请帮忙!

3 个答案:

答案 0 :(得分:2)

以下几点可能会让您觉得有趣/有用,可以告诉您的团队。

  • 不同的编译器以不同的方式破坏C ++名称。这个简单的名称修改问题可以通过显式的.def文件来规避。

  • 需要正确编译器选项的不同结构对齐问题(-mms-bitfields,...)。

  • 潜在异常和内存模型的基本冲突:

    • MSVC DLL中的new / delete或malloc / free不会与Cygwin newlib new / delete或malloc / free合作。一个人不能释放使用不同的new / malloc在函数中分配的空间。

    • MSVC DLL引发的异常不会被Cygwin可执行文件捕获,反之亦然。

    • 缓慢的GNU SJLJ异常模型(在GCC-3.x及更早版本中使用)与MSVC ++模型兼容,但是新的DWARF2模型(将由GCC-4.x使用) ,将是不相容的。

给出了一个更完整的解释here,我无耻地复制了上述内容。看到你使用MinGW,这应该是非常相关的。

另外,如果您还没有这样做,请查看this SO question的讨论。

答案 1 :(得分:2)

不同的编译器使用不同的运行时库。 std::stringstd::vector<int>std::shared_ptr都有不同的实现。类具有不同的布局(对齐和打包只是布局的一部分)。如果在任何地方甚至只有一个inline函数,以及在需要分配内存时创建对象,那么关于这种布局的假设会被烘焙到两个模块中。

C ++有一个定义规则的原因,一旦你开始混合编译器,甚至不同的编译器选项,就违反了该规则。

这些是可以安全分享的东西:

  • 标准布局数据专用类,只要您小心将deallocator与分配器匹配即可。您无法跨越图书馆边界。包装也需要在两侧设置相同的颜色。
  • 纯虚拟基类,仅包含纯虚拟实例成员函数。没有实例数据,也没有任何静态数据。接口之间没有继承。并且只允许具有实现接口的具体子类的模块在接口指针之间进行转换。

请注意,这些都不需要dllexport。只包含具有相同打包选项的相同头文件就足够了,因为函数是通过v表找到的,而不是通过DLL导入找到的。

当然,您还希望从DLL导出与C兼容的全局函数,以引导对象的创建。对于将使用__declspec(dllexport)或模块定义文件。此外,我建议extern "C"用于这些全球出口。

我强烈建议您阅读&#34;组件对象模型&#34; (COM),它有各种其他名称,如DCOM,ActiveX等。你不需要使用所有相同的机制,这会变得相当复杂,但试着至少理解&#34 ;仅与虚拟功能接口&#34;和&#34;引用计数与自我释放&#34;随着&#34;继承图由对象本身遍历&#34;方案提供了混合不同语言和编译器的能力。 (旁注:COM的存在是v-table-only类兼容的原因,因为COM是v-table布局的Windows标准。它与Windows一样接近ABI。)

答案 2 :(得分:0)

嗯..我以为只有扩展的dll才能加载c ++类 和扩展的dll适用于MFC,因此只有视觉工作室可以让我得到... ...