5

假设我有一个 C++ DLL。AFAIK,C++ 没有广泛采用的 ABI 标准,因此为了确保它工作并且不依赖于目标应用程序的编译器,我需要将我的库包装在 C 接口中。

有没有工具可以自动生成这样的界面?如果他们可以围绕 C 接口生成包装器以看起来好像它们是原始 C++ 对象,例如

Foo* f = new Foo();  // FooWrapper* fw = Foo_create();
f->bar("test");      // Foo_bar(fw, "test")

转换为使用生成的 C ABI 在我的库中调用的 C 函数。我知道 C++ 是一种相当复杂的语言,并不是所有东西都可以轻松地包装在 C 接口中,但我想知道是否有任何这样的解决方案甚至支持 C++ 语言的子集(也许在一些手动编写的 IDL/ 的帮助下) XML 文件)?

4

3 回答 3

4

如果您想要一种使 C++ 代码可从其他编译器/标准库调用的方法,您可以使用来自https://github.com/jbandela/cppcomponents的 cppcomponents 。完全披露 - 我是图书馆的作者。

这是一个简单的 hello world 示例

首先创建一个名为 library.h 的文件在这个文件中,您将定义组件

#include <cppcomponents/cppcomponents.hpp>

struct IPerson
:public cppcomponents::define_interface<cppcomponents::uuid<0xc618fd04,0xaa62,0x46e0,0xaeb8,0x6605eb4a1e64>>
{

    std::string SayHello();

    CPPCOMPONENTS_CONSTRUCT(IPerson,SayHello);



};

inline std::string PersonId(){return "library!Person";}

typedef cppcomponents::runtime_class<PersonId,cppcomponents::object_interfaces<IPerson>> Person_t;
typedef cppcomponents::use_runtime_class<Person_t> Person;

接下来创建 library.cpp 在这个文件中你将实现接口和组件

#include "library.h"

struct PersonImplementation:cppcomponents::implement_runtime_class<PersonImplementation,Person_t>
{

    std::string SayHello(){return "Hello World\n";}

};

CPPCOMPONENTS_DEFINE_FACTORY(PersonImplementation);

最后,这是使用您的实现的主程序(称为 example1.cpp)

#include "library.h"
#include <iostream>

int main(){
    Person p;
    std::cout << p.SayHello();

}

要构建程序,您需要下载 cppcomponents(只需从上面的 git 链接克隆)。它是一个只有头文件的库,只需要一个 c++11 编译器。

这是在 Windows 上构建它的方法

cl /EHsc example1.cpp /I pathtocppcomponents

g++ -std=c++11 library.cpp -o library.dll -shared -I pathtocppcomponents

其中 pathocppcomponents 是 cppcomponents 的目录。我假设你的路径中有 cl 和 g++。

要运行该程序,请确保 library.dll 与 example1.exe 位于同一目录并运行 example1.exe

该库需要相当兼容的 c++11 支持,因此它需要 MSVC 2013 Preview 和至少 g++ 4.7。该库适用于 Windows 和 Linux。

于 2013-07-22T17:54:19.647 回答
3

C++ 没有广泛采用的 ABI 标准

我很确定这有点夸张 - 没有那么多不同的编译器可用于任何给定的平台,因此为每个供应商生成一个 DLL 可能会更容易(例如 Microsoft、Windows 上的 GCC、Linux 上的 GCC , Sun and GCC for Solaris, GCC for MacOS - 据我所知,CLANG 与 GCC 兼容)。

添加 C 层接口基本上意味着接口层不得: 1. 使用任何需要特殊复制/分配/构造行为的对象。2. 使用任何“抛出”异常。3. 使用虚函数。穿过那个界面。

在我看来,“修复”由“缺乏 ABI”引起的问题,比制作一个适合 C++ 使用的好接口,中间有一个 C 接口更容易。

于 2013-07-18T23:36:17.217 回答
1

据我所知,答案是否定的,您应该自己通过一些“黑客”和修改来处理这个问题,例如,您的t变量std::string可能会“外部”到 C 接口,t.c_str()因为c_str返回一个const char *这是 C 完全可以理解的类型。

我个人认为 C++ 并不复杂,我也看不到“ABI 问题”,我的意思是没有什么是完美的,但您将整个代码库外部化到 C 以“解决”这个问题?首先使用 C,C 也不是容易处理的语言,例如在 C 中甚至没有“字符串”的概念,在 C++ 中解决的问题是微不足道的,同时保持一切类型安全,如果您想实现相同的目标,那么在 C 语言中确实具有挑战性。

我认为您在这方面走得太远了,而且您使事情变得复杂,因为现在您在最流行的平台上有 3 + 1 个主要选项:

  • libsupc++
  • libcxxrt
  • libc++abi
  • 加上无论 ABI 是否适用于您选择的 MSVC(也称为“只有上帝知道”)

对我来说,在 linux 上,libsupc++ 工作得很好,我正在关注 libc++abi 项目,我也没有看到任何大问题,唯一真正的问题是 llvm 目前基本上是一个面向 Apple 的项目,所以没有对其他平台的真正和良好的支持,但是 libc++abi 在 linux 上编译和工作也很好(虽然它基本上是无用和毫无意义的,在 linux 上已经有 libsupc++ 了。)。

我也永远不会在 Windows 下使用 MSVC,在我看来,最好坚持使用类似 GCC 的编译器,例如 mingw,您可以获得最前沿的功能,并且可以大大简化您的代码库和构建阶段。

于 2013-07-18T23:54:20.927 回答