C++;在linux平台上运行时加载共享库和提取类实现 在C++中,是否可以在执行时加载共享库?
我希望用户选择在运行时加载哪个共享库,而无需重新编译整个程序C++;在linux平台上运行时加载共享库和提取类实现 在C++中,是否可以在执行时加载共享库?,c++,linux,qt,qt4,shared-libraries,C++,Linux,Qt,Qt4,Shared Libraries,我希望用户选择在运行时加载哪个共享库,而无需重新编译整个程序 dlopen()是C的解决方案,但我的程序是用C++/Qt编写的,要提取的符号是Qt样式的类,是否有更“C++”的方法来实现这一点。是的,可以在大多数操作系统上实现您所描述的功能,但是,你如何做到这一点取决于系统,无论是什么系统,你都需要付出更多的努力才能实现这一点 一般步骤如下: 加载库 对于库中您感兴趣的每个符号,找到它并将其存储到一个变量以供以后使用。(这可以根据需要进行,而不是立即进行。) 例如,在*nix类型系统上的伪代码(
dlopen()
是C的解决方案,但我的程序是用C++/Qt编写的,要提取的符号是Qt样式的类,是否有更“C++”的方法来实现这一点。是的,可以在大多数操作系统上实现您所描述的功能,但是,你如何做到这一点取决于系统,无论是什么系统,你都需要付出更多的努力才能实现这一点
一般步骤如下:
// 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());
}
{
void*handle=dlopen(“libmyFunction.so”,);
if(!handle)return;//错误:找不到库!
int(*func)(=(int(*)dlsym(句柄,“myFunction”);
if(!func)return;//错误:找不到符号!
printf(“函数返回:%d\n”,func());
}
如果需要在Windows上执行此操作,则概念相同,但函数调用不同。您可以在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();
}
#包括
#包括
类动态库
{
公众:
动态_库();
虚拟整数和(整数长度,整数*数据);
};
typedef动态_库*(*get_object_func)();
typedef int(*调用函数)(int len,int*数据);
int main(int argc,char*argv[])
{
qcorea应用程序(argc、argv);
QLibrary library(“动态库”);
load();
如果(!library.isLoaded())
{
qDebug()如果目标库本身或至少其规范在您的控制下,那么您不应该使用QLibrary
-而是使用。它不需要通过指针调用,否则需要
<>如果你坚持使用<代码> DLOPEN//C>类似的机制,关于<代码> QLibrary < /C> >没有什么C特定的。明显的限制是,你要打开的库必须是用C++编译器编译的,它与你用来编译自己代码的AB兼容。C版本
除此之外,您还必须这样做。完成后,您可以使用与符号匹配的函数/方法指针调用符号。这是通过设计实现的。如果您希望创建对象的新实例,则需要库提供的静态工厂方法
如果库不提供工厂方法,则可以实现一个垫片库,该垫片库通过泛型名称链接到目标库,并提供工厂方法。您仍然需要通过函数/方法指针调用各个方法
创建一个临时文件夹
将垫片库复制到临时文件夹
将重命名为通用名称的目标库复制到临时文件夹中
保存LD\u LIBRARY\u PATH
环境变量的值
将临时文件夹前置到LD\u LIBRARY\u PATH
打开/加载库
还原LD\u LIBRARY\u PATH的保存值
当然,对于库公开的任何接口,都必须有头文件。通常情况下,只要有一个动态库文件,就无法重建头文件-主要是因为损坏的符号没有所用类型的完整结构信息。例如,即使可以找到给定类的构造函数,也不知道有多大是类实例(其sizeof
).这是什么平台?是的,这是可能的,但与运行时如何将共享库加载到程序中的操作系统无关。从代码中运行共享库有什么特殊问题?我想从库中提取的是qt类,我不知道在qt中,有一种机制可以做到这一点,或者没有。我已经把共享库的代码添加到答案中。正如你所看到的,外部“C”给了你一个访问C++类动态的可能性。必须吗?必须是虚拟的。因为我们在使用它时声明它,而不定义它。非常感谢,我还发现我无法从类中检索静态成员
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;
}