Qt 静态库和动态库

Qt 静态库和动态库

  • 创建和使用静态库
    • 创建静态库
    • 使用静态库的文件
  • 创建和使用动态库
    • 创建动态库
    • 使用动态库
      • 隐式链接调用共享库
      • 显示调用

创建和使用静态库

创建静态库

1.选择新建文件和项目。=>选择C++ Library
Qt 静态库和动态库_第1张图片
2.进入界面
类型选择:静态库
Qt 静态库和动态库_第2张图片
项目的名字和类的名字根据自己的实际的情况修改就行。

静态库项目可以使用MinGW或MSVC编译器编译,但是项目编译生成的文件与使用的编译器有关。若使用MSVC编译,编译后会生成一个库文件.lib;若使用MinGW编译,编译后会生成一个库文件.a。

然后根据自己需要选择编译成debug版本和release版本的静态库文件。

看一下.pro文件的内容:
TEMPLATE=lib 定义项目模板是库,而不是应用程序。
CONFIG += staticlib 配置项目为静态库。
TARGET = myStaticLib定义项目编译后生成的目标文件名称是myStaticLib。

使用静态库的文件

在自己的项目中,增加库就行。
1.选择外部库
Qt 静态库和动态库_第3张图片
2.把自己编译好的动态库增加到自己的项目的include的文件夹下面。包括头文件.h和动态库文件.lib。
选择静态库文件,选择自己的静态库的路径增加进去。
Qt 静态库和动态库_第4张图片
最后可以在.pro文件中看到,自动帮助我们增加了路径


win32:CONFIG(release, debug|release): LIBS += -L$$PWD/include/ -lmyStaticLibd
else:win32:CONFIG(debug, debug|release): LIBS += -L$$PWD/include/ -lmyStaticLibd

INCLUDEPATH += $$PWD/include
DEPENDPATH += $$PWD/include

win32-g++:CONFIG(release, debug|release): PRE_TARGETDEPS += $$PWD/include/libmyStaticLibd.a
else:win32-g++:CONFIG(debug, debug|release): PRE_TARGETDEPS += $$PWD/include/libmyStaticLibd.a
else:win32:!win32-g++:CONFIG(release, debug|release): PRE_TARGETDEPS += $$PWD/include/myStaticLibd.lib
else:win32:!win32-g++:CONFIG(debug, debug|release): PRE_TARGETDEPS += $$PWD/include/myStaticLibd.lib

注意:
如果你的静态的版本库与你现在项目的编译的编译器类型不同,或者编译的位数不同,会出现无法解析的外部符号。

创建和使用动态库

创建动态库

1.选择新建文件和项目。=>选择C++ Library
Qt 静态库和动态库_第5张图片
2.进入界面
类型选择:动态库
Qt 静态库和动态库_第6张图片
项目的名字和类的名字根据自己的实际的情况修改就行。

进去之后会发现我们的项目会多一个_global.h的文件
查看一下内容:

#ifndef DLL_GLOBAL_H
#define DLL_GLOBAL_H

#include 

#if defined(DLL_LIBRARY)
#  define DLL_EXPORT Q_DECL_EXPORT
#else
#  define DLL_EXPORT Q_DECL_IMPORT
#endif

#endif // DLL_GLOBAL_H

这里定义了符号DLL_EXPORT用于替代Qt的宏Q_DECL_EXPORT或Q_DECL_IMPORT。

可以到符号DLL_EXPORT,就是我们开始给起的项目的名字,我们需要在我们需要输出的地方使用这个宏来输出可以使用的对象。比如一个类,一个函数等。

注意:有时候我们看到文件输出了.dll,但是没有文件.lib,就是没有使用这个宏去输出我们的文件。

一个共享库导出给用户使用的类、符号、函数等都需要用宏Q_DECL_EXPORT来定义导出,一个使用共享库的应用程序需要通过Q_DECL_IMPORT导入共享库里的可用对象。

再看一下.pro文件:

Qt   += widgets
TARGET = mySharedLib		//生成的动态库的名字
TEMPLATE = lib				//库

DEFINES += MYSHAREDLIB_LIBRARY

目的文件准备好之后就可以编译生成DLL文件,根据使用的编译器不同,生成的文件有些区别。

若使用MSVC编译,编译后会生成.dll和.lib两个文件,.dll在运行应用程序时调用,.lib在应用程序隐式调用动态链接库时使用。
若使用MinGW编译,编译后会生成.dll和.a两个文件,.dll在运行应用程序时调用,.a在应用程序隐式调用动态链接库时使用。

使用动态库

两种调用方式:隐式链接(implicit linking)调用和显式链接(explicit linking)调用。

隐式链接调用是在编译应用程序时,有动态库的lib文件(或.a文件)和h头文件,知道DLL中有哪些接口类和函数,编译时就隐式地生成必要的链接信息,使用DLL中的类或函数时根据h头文件中的定义使用即可。应用程序运行时将自动加载DLL文件。隐式链接调用主要用于同一种编程软件(如Qt)生成的代码的共享。

显式链接调用是只有DLL文件,知道DLL里的函数原型,使用QLibrary类对象在应用程序里动态加载DLL文件,声明函数原型,并使用DLL里的函数。这种方式需要在应用程序里声明函数原型,并解析DLL里的函数。

隐式链接调用共享库

需要准备.h文件,_global.h文件,.lib文件。放到项目的include目录下。
然后增加库,跟静态的增加库是一样的。然后把.dll,文件放到程序的运行的位置就可以了。

查看一下.pro文件:
已经链接好.lib文件了

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

显示调用

说白了,就是只有有动态库.dll文件,和知道动态库中有什么函数,那么使用的时候,就能够直接调用动态库的文件,就是不需要连接什么。

显式链接调用共享库是通过QLibrary类实现的。QLibrary是与平台无关的,用于在运行时载入共享库,一个QLibrary对象只对一个共享库进行操作。

一般在QLibrary的构造函数中传递一个文件名,可以是带路径的绝对文件名,也可以是不带后缀的单独文件名。QLibrary会根据运行的平台自动查找不同后缀的共享库文件,例如Unix上是“.so”,Mac上是“.dylib”,Windows上是“.dll”。

例如简单调用

void MainWindow::on_pushButton_clicked()
{
   QLibrary myLib("DelphiDLL");//加载动态库文件
   if (myLib.isLoaded())
     QMessageBox::information(this,"信息","DelphiDLL.DLL已经被载入,第1处");
   typedef int (*FunDef)(int); 
   FunDef myTriple = (FunDef) myLib.resolve("triple"); //解析DLL中的函数
   int V=myTriple(ui->spinInput->value()); //调用函数
   ui->spinOutput->setValue(V);
   if (myLib.isLoaded())
     QMessageBox::information(this,"信息","DelphiDLL.DLL已经被载入,第2处");
}

QLibrary有几个函数用于DLL文件的载入与卸载:load()用于手动载入DLL文件到内存里,一般无需手工调用此函数,在DLL里的函数第一次被使用时QLibrary会自动调用此函数;isLoaded()用于判断DLL是否已经被载入内存;unload()用于将DLL从内存中卸载。

一个动态链接库在内存里只能有一个实例,也就是即使有多处调用了这个动态链接库里的函数,它也只会被载入一次,如果不是所有的实例都使用unload()卸载它,那么它会在应用程序退出时才卸载。

显式调用动态链接库里的函数,需要声明函数原型的类型,即:

typedef int (*FunDef)(int);
然后使用QLibrary的resolve()函数解析需要调用的函数。

FunDef myTriple = (FunDef) myLib.resolve(“triple”);
这样就定义了一个函数myTriple,用于实现DLL文件里的函数"triple"的功能,当然重新声明的函数名称可以和DLL里的函数名称完全相同。

你可能感兴趣的:(QT,qt)