【问题标题】:C++ load shared library and extract class implementations at runtime on linux platformC++在Linux平台运行时加载共享库并提取类实现
【发布时间】:2014-04-01 19:24:22
【问题描述】:

在 C++ 中,是否可以在执行时加载共享库?

我希望用户在运行时选择要加载的共享库,而不需要重新编译整个程序。

dlopen()是C的解决方案,但我的程序是用C++/Qt编写的,提取的符号是Qt风格的类,有没有更“c++”的方式来做到这一点。

【问题讨论】:

  • 这是什么平台?
  • 是的,这是可能的,但与c++qt 没有本质上的关系,它取决于操作系统如何在运行时将共享库加载到您的程序中。从您的代码中运行它有什么特别的问题?
  • 我想从lib中提取的是qt类,我不知道在qt中有没有这样的机制。

标签: c++ linux qt qt4 shared-libraries


【解决方案1】:

您可以在 Qt 中使用QLibrary 以两种方式完成此操作。以下示例在运行时以两种不同的方式从共享库调用函数:

#include <QLibrary>
#include <QDebug>

class  Dynamic_library
{
public:
    Dynamic_library();
    virtual int sum( int len, int * data );
};

typedef Dynamic_library * (*get_object_func)();
typedef int (*call_sum_func)(int len , int * data);

int main(int argc, char *argv[])
{
    QCoreApplication a(argc, argv);

    QLibrary library( "./dynamic_library" );
    library.load();
    if( !library.isLoaded() )
    {
        qDebug() << "Cannot load library.";
        return 0;
    }
    call_sum_func call_sum = (call_sum_func)library.resolve( "call_sum" );
    if( call_sum )
    {
        //Dynamic_library * obj=get_object();

        int * a=new int[3];
        a[0]=2;
        a[1]=3;
        a[2]=4;
        qDebug() << "sum of 2+3+4' = " << call_sum( 3, a ) <<"\n";

        delete [] a;
    }

    get_object_func get_object = (get_object_func)library.resolve( "get_object" );
    if( get_object )
    {
        Dynamic_library * obj=get_object();

        int * a=new int[3];
        a[0]=7;
        a[1]=8;
        a[2]=9;
        qDebug() << "sum of 7+8+9' = " << obj->sum(3, a );

        delete [] a;
    }

    return a.exec();
}

共享库的代码如下:

class DYNAMIC_LIBRARYSHARED_EXPORT Dynamic_library
{
public:
    Dynamic_library();
    virtual int sum( int len, int * data );
};

extern "C" Q_DECL_EXPORT Dynamic_library * get_object()
{
     return new Dynamic_library();
}

extern "C" Q_DECL_EXPORT int call_sum(int len, int * data)
{
     return Dynamic_library().sum(len,data);
}


Dynamic_library::Dynamic_library()
{

}

int Dynamic_library::sum( int len, int *data )
{
    int sum = 0;
    for(int i=0; i<len; ++i )
        sum += data[i];

    return sum;
}

【讨论】:

  • 我已将共享库的代码添加到答案中。如您所见,外部“C”使您可以动态访问 C++ 类。
  • “sum”的成员函数的“虚”声明是必须的吗?
  • 必须是虚拟的。因为我们声明了它,在使用的时候没有定义它。
  • 非常感谢,我也发现无法从类中检索静态成员
【解决方案2】:

如果目标库本身,或者至少它的规范在您的控制之下,那么您不应该使用QLibrary - 而是使用Qt plugin system。它不需要其他需要的通过指针调用体操。

如果你坚持使用类似dlopen 的机制,那么QLibrary 就没有C 特有的东西。明显的限制是,您尝试打开的库必须使用与用于编译您自己的代码的 ABI 兼容的 C++ 编译器进行编译。在 Windows 上,这实际上意味着使用相同的 MSVC 版本。

除此之外,您还必须look up the mangled version of the symbol。完成此操作后,您可以使用与其匹配的函数/方法指针调用该符号。这个won't work on constructors/destructors,设计使然。如果您希望创建新的对象实例,则需要库提供的静态工厂方法。

如果库不提供工厂方法,您可以实现一个 shim 库,该库通过通用名称链接到目标库并提供工厂方法。您仍然需要通过函数/方法指针调用各个方法。

  1. 创建一个临时文件夹。
  2. 将 shim 库复制到临时文件夹。
  3. 将重命名为通用名称的目标库复制到临时文件夹中。
  4. 保存LD_LIBRARY_PATH环境变量的值。
  5. 将临时文件夹添加到LD_LIBRARY_PATH
  6. 打开/加载库。
  7. 恢复LD_LIBRARY_PATH 的保存值。

当然,对于库公开的任何接口,您都必须拥有头文件。通常,仅给定一个动态库文件就无法对其进行重构-主要是因为损坏的符号没有所用类型的完整结构信息。例如,即使您可以找到给定类的构造函数,您也不知道该类实例有多大(它的sizeof)。

【讨论】:

    【解决方案3】:

    是的,可以在大多数操作系统上执行您所描述的操作,但是您如何执行取决于系统,并且无论系统如何,您都需要做更多的工作才能实现它。

    一般步骤是:

    1. 加载库
    2. 对于库中您感兴趣的每个符号,找到它并将其存储到一个变量中以供以后使用。 (这可以根据需要完成,而不是立即完成。)

    例如,在 *nix 类型系统上的伪代码(阅读:这不会编译!)中,假设您的共享库中有这个:

    // I'm declaring this _extern "C"_ to avoid name mangling, making it easier to
    // specify a symbol name for dlsym() later
    extern "C" int myFunction() {
        return 10;
    }
    

    假设它位于名为 libmyFunction.so 的库中。例如,您的主应用程序可以:

    {
        void *handle = dlopen("libmyFunction.so", <flags>);
        if (!handle) return; // error: cannot locate the library!
    
        int (*func)() = (int (*)())dlsym(handle, "myFunction");
        if (!func) return; // error: cannot locate the symbol!
    
        printf("The function returns: %d\n", func());
    }
    

    如果您需要在 Windows 上执行此操作,则概念相同,但函数调用不同。

    【讨论】:

      猜你喜欢
      • 2012-02-08
      • 1970-01-01
      • 2011-07-28
      • 1970-01-01
      • 2011-11-29
      • 1970-01-01
      • 1970-01-01
      • 2011-08-19
      相关资源
      最近更新 更多