【问题标题】:Portability of exporting a c++ class via virtual interface class通过虚拟接口类导出 c++ 类的可移植性
【发布时间】:2021-03-29 14:46:29
【问题描述】:

我想编写一个可以用作插件的库。该库是用 C++ 编写的,也应该在 C++ 代码中使用。我找到了this article,它描述了如何通过用户可见的纯虚拟接口结构导出 c++ 类。简而言之,代码如下:

struct VirtualInterface
{
    virtual MyExportedFunction() = 0;
}

class MyInterfaceImplementer : public VirtualInterface
{
    ...
    virtual MyExportedFunction(){...}
    ...
}

extern "C" MyAPI VirtualInterface* Factory(); // The only exported function

文章作者曾说过:

无法有效支持 COM 的假设 C++ 编译器是 注定在Windows市场被遗忘。这就是为什么,如今, 通过抽象接口从 DLL 公开 C++ 类将起作用 可靠地与 Windows 平台上的每个体面的 C++ 编译器一起使用。

我是否理解这种导出 C++ 类的方式依赖于编译器实现并且不能保证按标准工作?如果是的话,除了通过创建一个导出接口的每一个函数的 C 接口之外,是否有一种可移植的方式?

【问题讨论】:

  • 是的,C++ 没有标准的 ABI,因此对于健壮的应用程序,通常建议创建一个纯 C 包装器。该包装器还可以在边界处停止所有异常并将它们转换为老式 C 返回代码 - 原始但健壮。
  • @ErikAlapää 我的插件需要在 UNIX 系统上运行。所以听起来好像我必须忍受 C 出口。谢谢。
  • @PaulR。这一点意味着您可以将纯基于接口的库与任何 COM 友好的编译器一起使用。您还可以导出没有接口的类。在这种情况下,您必须保证库和用户模块都是使用相同的编译器和链接器构建的,具有相似的选项(例如调试或发布)。
  • 该标准没有提及 DLL 或共享库或可加载插件。实际上,您所描述的内容仅适用于所有常见平台。如果您只针对 C++ 用户,并且愿意假设他们将使用与您相同的 C++ 编译器,则无需诉诸 C 或 COM 或其他类似的废话。

标签: c++ shared-libraries language-lawyer


【解决方案1】:

您可以可移植地导出 C++ 类/接口on GNU/Linux and BSD because compilers support Itanium ABI

从 GCC 3.2 开始,用于 C++ 的 GCC 二进制约定基于书面的、供应商中立的 C++ ABI,该 ABI 旨在特定于 64 位 Itanium,但也包括适用于任何平台的通用规范。此 C++ ABI 也由其他编译器供应商在某些平台上实现,特别是 GNU/Linux 和 BSD 系统。我们一直在努力提供一个稳定的 ABI,它可以与未来的 GCC 版本兼容,但我们可能会遇到使这变得困难的问题。此类问题可能包括不同供应商对 C++ ABI 的不同解释、ABI 中的错误或不同编译器中 ABI 实现中的错误。当 G++ 生成可能与 C++ ABI 不兼容的代码时,GCC 的 -Wabi 开关会发出警告。

但是,如果 C++ 标准库中的类在接口中公开,则 API 的实现和使用者必须使用相同的 C++ 库实现:

与 C++ 编译器一起使用的 C++ 库包括标准 C++ 库,具有在 C++ 标准中定义的功能,以及语言运行时支持。运行时支持包含在 C++ ABI 中,但标准 C++ 库没有正式的 ABI。如果一个库的两个实现遵循另一个的事实上的 ABI,并且它们都使用相同的编译器构建,或者使用符合 C++ 编译器和运行时支持的相同 ABI 的编译器构建,则该库的两个实现是可互操作的。

当 G++ 和另一个 C++ 编译器符合相同的 C++ ABI,但它们通常使用的标准 C++ 库的实现不遵循标准 C++ 库的相同 ABI 时,使用这些编译器构建的目标文件可以用于只有当他们使用相同的 C++ 库时才能使用相同的程序。这需要在调用未使用常用库的编译器时指定 C++ 库头文件的位置。

由于上述支持 COM 的要求,这也可能适用于 Windows 编译器。不过,析构函数存在一个问题:COM 不使用析构函数,因此支持 COM 的两个编译器在将析构函数指针放在 v-table 中的位置上可能会有所不同。

【讨论】:

    【解决方案2】:

    在 Doom 3 游戏中,引擎可执行文件 Doom3.exegamex86.dll 动态加载游戏玩法。游戏引擎接口完全按照您的描述通过虚拟函数公开(请参阅review)。这在 Windows 和 Linux 上运行良好,允许创建模组(例如 TheDarkMod 曾经那样生活)。

    与动态链接相关的常见问题当然适用:

    1. CRT 库:静态链接意味着您必须小心您通过 DLL 边界传递的内容。动态链接意味着每个人都必须使用相同的主要版本的编译器,至少在 Visual Studio 的情况下。
    2. 在界面中使用 STL 是一个非常糟糕的主意,因为这样每个人都必须在 Windows 上使用相同的主要版本的 Visual Studio 和相同类型的 CRT(调试/发布)。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2012-06-17
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多