在C ++中,是否可以在执行时加载共享库?
我希望用户选择在运行时加载哪个共享库,而无需重新编译整个程序。
dlopen()
是C的解决方案,但是我的程序是用C ++ / Qt编写的,要提取的符号是Qt样式的类,有没有更“c ++”的方法来做到这一点。
答案 0 :(得分:5)
您可以使用QLibrary
以两种方式在Qt中执行此操作。以下示例在运行时以两种不同的方式从共享库调用函数:
#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;
}
答案 1 :(得分:2)
如果目标库本身或至少其规格在您的控制之下,那么您不应该使用QLibrary
- 而是使用Qt plugin system。它不需要另外需要的呼叫指针体操。
如果您坚持使用类似dlopen
的机制,那么QLibrary
没有任何特定于C的内容。显而易见的限制是,您尝试打开的库必须使用C ++编译器进行编译,该编译器与您用于编译自己的代码的编译器兼容。在Windows上,这实际上意味着使用相同的MSVC版本。
除此之外,你必须look up the mangled version of the symbol。完成后,可以使用与其匹配的函数/方法指针调用符号。这是won't work on constructors/destructors,按设计。如果您希望创建对象的新实例,则需要库提供的静态工厂方法。
如果库不提供工厂方法,则可以实现通过通用名称链接到目标库的填充程序库,并提供工厂方法。您仍然需要通过函数/方法指针调用各个方法。
LD_LIBRARY_PATH
环境变量的值。LD_LIBRARY_PATH
。LD_LIBRARY_PATH
的已保存值。 当然,您必须拥有库公开的任何接口的头文件。一般情况下,只能通过动态库文件重建它 - 主要是因为受损的符号没有所用类型的完整结构信息。例如,即使您可以找到给定类的构造函数,您也不会知道类实例有多大(sizeof
)。
答案 2 :(得分:0)
是的,您可以在大多数操作系统上执行您所描述的操作,但是您的操作方式取决于系统,无论系统如何,它都可以为您提供更多的工作。
一般步骤如下:
例如,在* 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上执行此操作,概念是相同的,但函数调用是不同的。