创建和使用静态库
创建静态库
1.选择新建文件和项目。=>选择C++ Library 2.进入界面 类型选择:静态库 项目的名字和类的名字根据自己的实际的情况修改就行。
静态库项目可以使用MinGW或MSVC编译器编译,但是项目编译生成的文件与使用的编译器有关。若使用MSVC编译,编译后会生成一个库文件.lib;若使用MinGW编译,编译后会生成一个库文件.a。
然后根据自己需要选择编译成debug版本和release版本的静态库文件。
看一下.pro文件的内容: TEMPLATE=lib 定义项目模板是库,而不是应用程序。 CONFIG += staticlib 配置项目为静态库。 TARGET = myStaticLib定义项目编译后生成的目标文件名称是myStaticLib。
使用静态库的文件
在自己的项目中,增加库就行。 1.选择外部库 2.把自己编译好的动态库增加到自己的项目的include的文件夹下面。包括头文件.h和动态库文件.lib。 选择静态库文件,选择自己的静态库的路径增加进去。 最后可以在.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 2.进入界面 类型选择:动态库 项目的名字和类的名字根据自己的实际的情况修改就行。
进去之后会发现我们的项目会多一个_global.h的文件 查看一下内容:
#ifndef DLL_GLOBAL_H
#define DLL_GLOBAL_H
#include <QtCore/qglobal.h>
#if defined(DLL_LIBRARY)
# define DLL_EXPORT Q_DECL_EXPORT
#else
# define DLL_EXPORT Q_DECL_IMPORT
#endif
#endif
这里定义了符号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");
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里的函数名称完全相同。
|