【Qt】在程序运行时加载共享库并解析调用库中函数

一个QLibrary对象的实例操作一个共享的对象文件(我们称之为“库”)。在Qt中,QLibrary以平台独立的方式提供了对库中功能的访问。我们可以在QLibrary构造函数中传递库文件名,也可以使用setFileName()显式地设置库文件名。当加载库时,QLibrary会搜索操作系统下特定的库位置(例如Unix系列操作系统上的LD_LIBRARY_PATH)。如果文件名使用了绝对路径,那么又会有不同的搜索形式。

如果文件名是绝对路径,则会先尝试加载该路径下的库。如果找不到库文件,QLibrary会使用不同平台下特定的文件前缀(如Unix和Mac上的“.lib”、Unix上的".so"。Mac上的“dylib”,Windows上的“.dll”)。

如果文件路径不是绝对的,那么QLibrary则会修改搜索顺序,首先尝试搜索系统特定的前缀和后缀,然后搜索指定的文件路径。

好啦,上文则是QLibrary的大概使用方法和相关规则。

一些常用的成员操作

在实际开发中,较常使用的函数是load(),该函数用于动态加载库文件,然后我们则使用isLoaded()检查加载是否成功。有效的库文件后缀如下表所示:

再库文件被加载后,我们需要使用resolve()函数去解析库中的符号。如果库没有被加载,resolve()函数还会隐式尝试去加载它。

在实际使用中,我们可以使用多个QLibrary实例来访问相同的库。一旦库被加载,它将一直保存在内存中,直到应用程序终止才会销毁。我们还可以尝试使用unload()卸载一个库,但如果QLibrary的其他实例正在使用该库,该函数将会执行失败。

QLibrary的典型用法是解析库中导出的符号,并调用该符号所代表的使用C语言编写的函数。例如下面的代码片段会加载一个库,并解析“mysymbol”符号,并在解析成功后调用该函数。如果出现错误,例如库文件不存在或符号没有定义,此刻函数指针将为nullptr,那么该函数则不会被调用。

QLibrary myLib("mylib");
typedef void (*MyPrototype)();
MyPrototype myFunction = (MyPrototype) myLib.resolve("mysymbol");
if (myFunction)
    myFunction();

以上代码片段中:首先使用QLibrary加载一个库;然后定义了一个函数指针MyPrototype类型;接着通过QLibrary的resolve()函数解析库中的符号,并将结果赋值给myFunction,如果myFunction不为nullptr,则调用该函数。

【注意】对于使用QLibrary来进行库文件的解析,符号必须从库中导出是一个C语言编写的函数,这样才能使resolve()能得以正常解析。这意味着:如果标准库是用c++编译器编译的,函数则必须封装在extern "C"块中。例如下列的使用场景:

首先,resolve()函数原型如下:

QFunctionPointer QLibrary::resolve(const char *symbol)

此成员函数返回导出符号的地址。如果符号无法解析或库无法加载,则该函数返回nullptr。

例如下列代码:

typedef int (*AvgFunction)(int, int);

AvgFunction avg = (AvgFunction) library->resolve("avg");
if (avg)
    return avg(5, 8);
else
    return -1;

在上述代码中,avg符号必须从库中导出为C函数。在Windows中,还必须使用__declspec(dllexport)编译器指令显式地从DLL中导出该函数:

extern "C" MY_EXPORT int avg(int a, int b)
{
    return (a + b) / 2;
}

MY_EXPORT宏定义如下:

#ifdef Q_OS_WIN
#define MY_EXPORT __declspec(dllexport)
#else
#define MY_EXPORT
#endif

载入标志

在使用QLibrary载入库的时候,我们可以使用setLoadHints()设置载入标志。该标志由enum QLibrary::LoadHint枚举来定义,这些值表示在加载库的时候如何解析符号,具体类型和含义如下表所示:

常量数值描述
QLibrary::ResolveAllSymbolsHint0x01在加载库时解析库中的所有符号,而不仅仅是在调用resolve()时解析。
QLibrary::ExportExternalSymbolsHint0x02导出库中未解析、外部符号,以便在其他动态加载的库中进行解析。
QLibrary::LoadArchiveMemberHint0x04允许库的文件名指定存档文件中的特定对象文件。如果给出了这个提示,那么库的文件名包含一个路径,它是对存档文件的引用,后面的名称是对存档成员的引用。
QLibrary::PreventUnloadHint0x08如果调用close(),防止从地址空间中卸载库。如果在后续调用open(),库的静态变量不会被重新初始化。
QLibrary::DeepBindHint0x10指示链接器在解析加载库中的外部符号时,优先选择在加载库中的定义,而不是加载应用程序中导出的定义。此选项仅支持linux平台

注意

在实际使用QLibrary的过程中,其库需要是使用C语言编译器编译导出的接口。

  • 2
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值