Qt之在运行时加载共享库

简述

在 Windows 上,共享库由 .dll 表示;在 Linux 上,由 .so 表示。一个共享库中的符号被设计为导出的,以便客户端可以从中导入符号。

要使用共享库,除了 Qt之创建并使用共享库 中介绍的方式之外,Qt 还提供了一种机制,可以在运行时加载共享库,通过 QLibrary 来实现。

版权所有:一去丶二三里,转载请注明出处:http://blog.csdn.net/liang19890820

认识 QLibrary

QLibrary 用于在运行时加载共享库,一个完整的加载流程大概分为以下几步:

  • 构造 QLibrary 实例
  • setFileName():指定共享库的文件名(也可以通过 QLibrary 的构造函数来设置)
  • load():动态加载共享库(isload() 检查加载是否成功)
  • resolve():解析共享库中的符号(如果库还没有加载,那么 resolve() 将隐式地尝试加载)
  • unload():卸载共享库

QLibrary 有一个很强大的特性 - 在运行时对共享库提供了平*立的访问。对于库路径,QLibrary 在内部会做以下处理:

  • 如果文件名是绝对路径,则首先尝试加载该路径。若无法找到文件,则尝试使用不同平台的特定文件前缀(例如:Unix 和 Mac 上的 lib)和后缀(例如:Unix 上的 .so、Mac 上的 .dylib、或 Windows 中的 .dll)的名称。
  • 如果文件路径不是绝对的,那么 QLibrary 会修改搜索顺序,首先尝试系统特定的前缀和后缀,然后再指定文件路径。

这使得可以指定仅由其 basename(即:没有 .dll.so 后缀)标识的共享库,因此相同的代码可以在不同的操作系统上工作。尽管如此,但仍建议尽量减少查找库的次数。

注意: 一个共享库可以被 QLibrary 的多个实例访问,加载完成后,库将一直保存在内存中,直到应用程序终止。在使用 unload() 卸载库时,如果 QLibrary 的其他实例使用了相同的库,那么调用将失败,并且只有当每个实例都调用 unload() 时才会卸载。

使用 QLibrary 的优点

在运行时使用 QLibrary 加载共享库,有很多优点:

  • 无需使用 .h 头文件和 .lib 文件,就可以编译应用程序。
  • 只需将 dll 文件和可执行程序放在一起
  • 可以在没有 dll 的情况下启动可执行程序,因为 dll 将在运行时(按需)加载。
  • 有助于生成一个较小的可执行程序

创建共享库

Qt之创建并使用共享库 一样,在 Qt Creator 中创建两个项目:

  • SharedLib:是一个 C++ 共享库项目,其中有一个导出符号。
  • SharedLibClient:是一个 Qt 控制台应用程序,在运行时调用 SharedLib。

sharedlib_global.h 可以确保正确的宏能够被调用:

#ifndef SHAREDLIB_GLOBAL_H
#define SHAREDLIB_GLOBAL_H

#include <QtCore/qglobal.h>

#if defined(SHAREDLIB_LIBRARY)
#  define SHAREDLIBSHARED_EXPORT Q_DECL_EXPORT
#else
#  define SHAREDLIBSHARED_EXPORT Q_DECL_IMPORT
#endif

#endif // SHAREDLIB_GLOBAL_H

sharedlib.h 包含了导出的符号:

#ifndef SHAREDLIB_H
#define SHAREDLIB_H

#include "sharedlib_global.h"

extern "C" {
    SHAREDLIBSHARED_EXPORT int subtract(int x, int y);
}

#endif // SHAREDLIB_H

sharedlib.cpp 包含了具体的实现:

#include "sharedlib.h"

int subtract(int x, int y)
{
    return x - y;
}

注意: 对于要解析的函数名,必须将其导出为 C 函数。这意味着如果库是用 C++ 编译器编译的,那么函数必须被包装在一个 extern "C" 块中。

此外,还必须使用 Q_DECL_EXPORTQ_DECL_IMPORT 从库中显式导出该函数。

在运行时加载共享库

创建一个简单的客户端(SharedLibClient) - Qt Console Application,它将使用 SharedLib 库中的 subtract() 函数。效果如下:

Qt之在运行时加载共享库

在 main.cpp 文件中,使用 QLibrary 在运行时加载共享库:

#include <QCoreApplication>
#include <QLibrary>
#include <qDebug>

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

    // SharedLibd.dll 与可执行程序位于同一目录
    QLibrary lib("SharedLibd");

    // 加载共享库
    if (lib.load()) {
        typedef int (*Fun)(int, int);
        // 解析符号
        Fun sub = (Fun) lib.resolve("subtract");
        if (sub) {
            int result = sub(5, 2);
            qDebug() << result;
        } else {
            qDebug() << "Can not resolve subtract";
        }
        // 卸载共享库
        lib.unload();
    } else {
        qDebug() << lib.errorString();
    }
    return a.exec();
}

在 Debug 模式下运行项目,结果会显示在控制台输出上。

上一篇:C++模版方法模式


下一篇:FreeStor采用全新技术全面应对数据管理的现实挑战