【问题标题】:Create automatic C wrapper for C++ library?为 C++ 库创建自动 C 包装器?
【发布时间】:2013-07-18 23:27:59
【问题描述】:

假设我有一个 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 文件)?

【问题讨论】:

  • 遇到模板和异常时会遇到麻烦。
  • @MooingDuck:我原以为模板可能会出现问题。但是模板不是总是由目标编译器编译的吗?这不就是为什么它们总是需要在头文件中定义吗?
  • true,如果你不是 wrappipng 模板类/函数,而只是包装模板实例,那么你很好。
  • cpp2c.webs.com 声称可以这样做,但我没有尝试过,它说:“Cpp2C 是一个 Python 脚本。 Cpp2C 已经用 Python 2.6 测试过,……它还没有用 Python 3 测试过。”

标签: c++ c wrapper abi


【解决方案1】:

如果您想要一种方法使 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。

【讨论】:

  • 这更接近我的需要,尽管它仍然需要手动编写大量代码,这增加了定义接口所需的时间和出错的可能性。但是,我相信使用您的库从 IDL 到 C 的某种翻译器将允许更简单地创建此类接口。你考虑过这种方法吗?
  • 您对 IDL 有什么想法?能举个简单的例子吗?
  • 我已经开始在这里画一些东西了:tinypaste.net/gQnpIB8j,但是它不完整。
  • 该网站似乎已更改其托管并且当前不可用。我已经删除了我上传的截图,因为这个问题与我无关。
【解决方案2】:

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

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

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

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

【讨论】:

  • 我仍然认为这是一个更好的解决方案。你不能从调试代码链接到发布库吗?如果我没记错的话,你以前可以。
  • 理论上可以,但如果这些链接与 CRT 的其他发布/调试版本链接,则会出现链接器错误。
【解决方案3】:

据我所知,答案是否定的,您应该自己通过一些“黑客”和修改来处理这个问题,例如您的 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,您可以获得最前沿的功能,并且可以大大简化您的代码库和构建阶段。

【讨论】:

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