除了静态库,Qt还可以创建共享库,也就是Windows平台上的动态链接库。动态链接库项目编译后生成DLL文件,DLL文件在windows平台上应用广泛。DLL文件是在应用程序运行时加载的,不像静态库那样在编译期间就连编到应用程序里。若更新了DLL文件版本,只要接口未变,应用程序依然可以调用。
调用动态链接库有两种形式,隐式链接(implicit linking)调用和显式链接(explicit linking)调用。
隐式链接调用是在编译应用程序时,有动态库的lib文件(或.a文件)和h头文件,知道DLL 中有哪些接口类和函数,编译时就隐式地生成必要的链接信息,使用DLL中的类或函数时根据h 头文件中的定义使用即可。应用程序运行时将自动加载DLL文件。隐式链接调用主要用于同一种编程软件(如Qt)生成的代码的共享。
显式链接调用是只有DLL文件,知道DLL里的函数原型,使用QLibrary类对象在应用程序 里动态加载DLL文件,声明函数原型,并使用DLL里的函数。这种方式需要在应用程序里声明函数原型,并解析DLL里的函数。
本文以一个示例,介绍如何创建共享库,并隐式调用该共享库。
创建共享库
创建共享库项目,单击 Qt Creator 的 “File” 一 “New File or Project” 菜单项,在 New File or Project对话框中选择Projects组里的Library,在右侧的具体类别中再选择C++ Library,单击 “Choose…”按钮后出现如图所示的向导对话框。
给项目命名,例如mySharedLib,再选择项目保存目录。单击“Next”按钮继续。
在此对话框的Type下拉列表框里选择Shared Library,选择需要包含的Qt模块,输入类的名称,这里仍然输入类名称为QDialogPen,再下一步结束即可。
由向导生成的 mySharedLib 项目包含文件 mySharedLib.pro、qdialogpen.h 和 qdialogpen.cpp。此外还有一个特殊的头文件mySharedLib_Global.h,文件的内容如下:
#ifndef MYSHAREDLIB_GLOBAL_H
#define MYSHAREDLIB_GLOBAL_H
#include <QtCore/qglobal.h>
#if defined(MYSHAREDLIB_LIBRARY)
# define MYSHAREDLIB_EXPORT Q_DECL_EXPORT
#else
# define MYSHAREDLIB_EXPORT Q_DECL_IMPORT
#endif
#endif // MYSHAREDLIB_GLOBAL_H
这里定义了符号MYSHAREDLIB_EXPORT用于替代Qt的宏Q_DECL_EXPORT或Q_DECL_IMPORT。
一个共享库导出给用户使用的类、符号、函数等都需要用宏Q_DECL_EXPORT来定义导出, 一个使用共享库的应用程序需要通过Q_DECL_IMPORT导入共享库里的可用对象。
在mySharedLib.pro文件里增加了符号MYSHAREDLIB_LIBRARY的定义,下面是 mySharedLib.pro 文件的主要内容:
Qt += widgets
TARGET = mySharedLib
TEMPLATE = lib
DEFINES += MYSHAREDLIB_LIBRARY
自动生成的qdialogpen.h文件里的内容是对QDialogPen类的定义,在类名称前使用了宏 MYSHAREDLIB_EXPORT,定义 QDialogPen 为一个导出的类。
#include "mySharedLib_global.h"
class MYSHAREDLIB_EXPORT QDialogPen
{
public:
QDialogPen();
};
将定义好的静态库项目(参见前一篇文章:从零开始学Qt(68):进阶!创建和使用静态链接库)里的文件qdialogpen.h、qdialogpen.cpp和qdialogpen.ui复制到本项目目录下,覆盖自动生成的初始文件,但是修改文件qdialogpen.h里的类的定义,在类名称前增加MYSHAREDLIB_EXPORT宏,并加入mySharedLib_Global.h的包含语句。
项目的文件准备好之后就可以编译生成DLL文件,根据使用的编译器不同,生成的文件有些区别。
- 若使用MSVC编译,编译后会生成mySharedLib.dll和mySharedLib.lib两个文件, mySharedLib.dll在运行应用程序时调用,mySharedLib.lib在应用程序隐式调用动态链接库时使用。
- 若使用MinGW编译,编译后会生成mySharedLib.dll和libmySharedLib.a两个文件, mySharedLib.dll在运行应用程序时调用,libmySharedLib.a在应用程序隐式调用动态链接库时使用。
采用debug和release不同模式生成的文件只能当应用程序在debug或release模式下编译或调用。
使用共享库
创建一个基于QMainWindow的应用程序shareLibUser,程序功能与静态库LibUser项目一 样,将LibUser项目的mainwindow相关3个文件mainwindow.h、mainwindow.cpp 和 mainwindow.ui复制到shareLibUser项目下,替换自动生成的文件。
在shareLibUser项目文件目录下新建一个include目录,将mySharedLib项目的两个头文件 qdialogpen.h和mysharedlib_global.h复制到此目录下。
若使用MSVC编译器,将release版本的mySharedLib.lib复制到此目录下,debug 版本的 mySharedLib.lib 更名为 mySharedLibd.lib复制到此目录下;
若使用MinGW编译器,则复制release版本的libmySharedLib.a,debug版本的 libmySharedLib.a更名为 libmySharedLibd.a 复制到此目录下。
为应用程序增加动态链接库,右键单击shareLibUser项目节点,在快捷菜单里单击“Add Library…”菜单项,在出现的向导对话框里首先选择添加的库类型为“External Library”,在向导第二步设置导入的动态库文件(见图)。
在图中,选择项目include目录下的mySharedLib.lib文件或libmySharedLib.a作为库文件,其他设置如图所示。
完成后在shareLibUser.pro文件中自动增加项目设置的语句如下:
win32:CONFIG(release, debug|release): LIBS += -L$PWD/include/ -lmySharedLib
else:win32:CONFIG(debug, debug|release): LIBS += -L$PWD/include/ -lmySharedLibd
INCLUDEPATH += $PWD/include
DEPENDPATH += $PWD/include
项目编译时,会根据当前是release还是debug模式,自动添加相应的库文件。这里添加库文件只是使用了动态库的导出定义,而不是将库的实现代码连接到应用程序的可执行文件里。
主窗体类MainWindow的功能与调用静态库的程序完全一致,调用共享库里的类QDialogPen也无需特别说明,只需包含头文件qdialogpen.h即可。
shareLibUser项目可以用MinGW或MSVC编译器编译,运行效果如图所示。
注意必须将动态链接库文件mySharedLib.dll复制到可执行文件的目录下,程序才可以正常运行。 mySharedLib.dll的debug和release版本必须分别用于应用程序的debug和release版本,否则运行时出错。
使用动态链接库可以很方便地扩展应用程序的功能,但是DLL文件需要随应用程序一起发 布,并且编译DLL和应用程序的Qt版本最好保持一致,否则需要考虑二进制兼容问题。
本文暂时没有评论,来添加一个吧(●'◡'●)