首页 > 解决方案 > 为使用 dlopen() 加载的类自动创建包装器

问题描述

我正在编写一个代理类,它加载一个共享库dlopen()并将其成员函数转发给在幕后加载的共享对象内的代理类实例的适当成员。

例如,共享对象有一个Person类:

class Person
{
    ...
    void setName(std::string name);
};

我添加了一个包含person.h标头并定义以下符号的包装文件:

extern "C" {
    void Person_setName(void* instancePointer, std::string name);
}

此调用仅转发给作为第一个参数的 person 对象,extern "C"以避免整个名称修改问题。在客户端,我编写了一个Person具有相同成员的类,该类包含指向包装类的指针并转发所有调用。

现在出现了一些问题:

  1. 有没有更好的方法来实例化和使用加载的共享对象中的类?我发现了一些其他解决方案可以在没有包装器的情况下生存,但是在 Usenet 上不鼓励它并且高度依赖 GCC 及其版本以及未定义的行为,所以我决定反对这条路线。
  2. 有没有办法自动创建这些包装器?它们都只是添加第一个参数,该参数是指向每个方法的实例的指针并转发给真实的东西。必须有一些模板魔法,不是吗?目前我正在使用一些宏来完成这项工作,但我会对模板解决方案感兴趣。
  3. 也许有一些工具可以自动做这样的事情,比如SWIG?据我所见, SWIG只是用于将 C++ 接口导出到高级语言。

标签: c++templatesshared-librariesdlopen

解决方案


有没有更好的方法来实例化和使用加载的共享对象中的类?

如果您想安全并支持任何共享对象(即由任何编译器/标志等编译),那么不行:您必须通过 C ABI。

请记住,您也不应该在接口中使用 C++ 对象,例如std::string您传入的Person_setName.

有没有办法自动创建这些包装器?必须有一些模板魔法,不是吗?目前我正在使用一些宏来完成这项工作,但我会对模板解决方案感兴趣。

不,您不能即时创建成员函数(我们还没有反射、元类和类似的编译时特性)。

它们都只是添加第一个参数,该参数是指向每个方法的实例的指针并转发给真实的东西。

当然,您可以创建一个将参数转发给给定extern "C"函数的可变参数模板,但与简单地调用 C 函数相比,您并没有真正从中获得任何有用的东西。换句话说,不要那样做:要么创建一个适当的 C++ 类,要么让用户调用 C 函数。

也许有一些工具可以自动做这样的事情,比如 SWIG?据我所见,SWIG 只是用于将 C++ 接口导出到高级语言。

我过去曾使用Clang 的工具支持来执行类似的任务作为预构建步骤,所以它确实是可能的!


推荐阅读