Qt动态连接库/静态连接库创建与使用,QLibrary动态加载库
博客地址已更改,文章数量较多不便批量修改,若想访问源文请到 coologic博客 查阅,网址:www.coologic.cn
如本文记录地址为 techieliang.com/A/B/C/ 请改为 www.coologic.cn/A/B/C/ 即可查阅
版权声明:若无来源注明,Techie亮博客文章均为原创。 转载请以链接形式标明本文标题和地址:
本文标题:Qt动态连接库/静态连接库创建与使用,QLibrary动态加载库 本文地址:https://www.techieliang.com/2017/12/680/
1. 动态连接库创建与使用
1.1. 项目创建
注意选择成shared library
此时新建的项目pro文件:
- QT -= gui
- TARGET = library
- TEMPLATE = lib
- DEFINES += LIBRARY_LIBRARY
- DEFINES += QT_DEPRECATED_WARNINGS
- SOURCES += \
- library.cpp
- HEADERS += \
- library.h
- unix {
- target.path = /usr/lib
- INSTALLS += target
- }
注意其Template为lib,且声明了一个LIBRARY_LIBRARY
对于global.h文件建议直接拷贝到library.h,这样发布的时候只需要给别人一个.h文件
library.h
- #ifndef LIBRARY_H
- #define LIBRARY_H
- #include <QtCore/qglobal.h>
- #if defined(LIBRARY_LIBRARY)
- # define LIBRARYSHARED_EXPORT Q_DECL_EXPORT
- #else
- # define LIBRARYSHARED_EXPORT Q_DECL_IMPORT
- #endif
- class LIBRARYSHARED_EXPORT Library {
- public:
- Library();
- int sum(int a, int b);
- };
- int LIBRARYSHARED_EXPORT sum(int a, int b);
- #endif // LIBRARY_H
pro声明的宏在这里用上了,做了一个判断,如果有定义则LIBRARYSHARED_EXPORT=Q_DECL_EXPORT,否则等于Q_DECL_IMPORT,也就是说在这个lib项目里是导出的意思,在其他项目因为给别人的只有.h文件并没有LIBRARY_LIBRARY的定义,所以是导入。从而实现不做任何修改即可发布.h文件。
将global.h拷贝到library.h也是为了只提供一个文件,否则若忘记了提供global.h调用方会提示缺少文件。
library.cpp
- Library::Library() {
- }
- int Library::sum(int a, int b) {
- return a+b;
- }
- int sum(int a, int b) {
- return a+b;
- }
此时直接Ctrl+B构建即可liblibrary.a、library.dll、library.o三个文件(MinGW版,VS的会有lib文件),提供给调用方*.h和*.dll文件即可(windows,linux共享库是*.so)
注意生成库也区分debug和release,debug的库内带有调试代码,一般debug的库文件名最后是d也就是
1.2. 调用-使用.h文件
建立一个Qt Console Application项目,将library.dll和library.h文件拷贝到项目目录下(和新项目的main.cpp在一起即可)
默认pro文件:
- QT -= gui
- CONFIG += c++11 console
- CONFIG -= app_bundle
- DEFINES += QT_DEPRECATED_WARNINGS
- SOURCES += main.cpp
在打开的pro项目右键,选择添加库(Add library),可以把dll文件包含到项目里,如果不包含此处选择外部库(External Library)
在pro文件最后添加
LIBS += library.dll
简单的写法是上面的样子,建议使用完整的写法:
LIBS += -LD:/my_program_design/dll_test/test_library_by_header/ -llibrary
+=前后允许有空格? -L和路径名不可有空格?? -l前面有空格后面不可有空格要紧跟文件名?? 文件名不需要后缀,系统会自动识别是dll还是lib
文件名是library,前面加了个-l变成了-llibrary,别忘了-l
main.cpp
- #include <QCoreApplication>
- #include <library.h>
- #include <QDebug>
- int main(int argc, char *argv[]) {
- QCoreApplication a(argc, argv);
- qDebug()<<sum(1,2);//测试c函数
- Library t;
- qDebug()<<t.sum(1,2);//测试类函数
- return 0;
- }
此时运行,可以生成成功,但是会报错,因为dll文件还需要拷贝到生成的exe文件目录,拷贝后再运行即可
2. 静态库创建及使用
2.1. 创建
见动态库第二图,创建时不要选择shared,选择静态连接库Statically Linked Library。
创建项目以后没有什么特色,不会有global.h文件也不会有一个export、import的定义,因为静态库不需要导入导出,生成库提供给使用者,使用者在编译时会将代码需要的代码编译到自己的项目中,不需要附带dll/lib等文件。
先看pro文件:
- QT -= gui
- TARGET = static_library
- TEMPLATE = lib
- CONFIG += staticlib
- SOURCES += \
- static_library.cpp
- HEADERS += \
- static_library.h
- unix {
- target.path = /usr/lib
- INSTALLS += target
- }
相比于动态链接库差异是增加了CONFIG += staticlib 删掉了DEFINES
.h和.cpp文件和动态库一样,只不过没有了LIBRARYSHARED_EXPORT
然后运行就会生成文件libstatic_library.a和static_library.o文件(MinGW,VS是lib文件)
2.2. 使用
和动态库一样新建个项目,把libstatic_library.a或者lib文件以及static_library.h考到项目
在pro文件增加:
LIBS += -LD:/my_program_design/dll_test/test_static_library/ -llibstatic_library
main.cpp文件:
- #include <QCoreApplication>
- #include <static_library.h>
- #include <QDebug>
- int main(int argc, char *argv[]) {
- QCoreApplication a(argc, argv);
- qDebug()<<sum(1,2);
- Static_library l;
- qDebug()<<l.sum(1,2);
- return 0;
- }
运行即可,这里就不需要吧.a文件复制到程序目录了,因为静态库编译的时候已经把需要的内容编译到exe程序了。
3. QLibrary动态加载动态库
3.1. 介绍
在动态库使用那里,直接编译运行会无法打开,把dll文件拷贝到运行目录才能打开程序,否则会提示缺少文件,然后就没有然后了。。。
不知道是否注意到有些程序是主动提示缺少文件错误的?会在程序运行到需要库文件时提示缺少此库,并且可以自定义提示内容,而不是用系统默认的错误提示,若想实现此功能需要动态加载。当然在库供应方只给了dll文件没给.h的时候也能使用,换句话说动态加载方式在编写项目时不需要.h文件,也不需要在pro文件增加“libs+=”
先看帮助文档:http://doc.qt.io/qt-5/qlibrary.html
接口很简单:
- QLibrary(QObject *parent = Q_NULLPTR)
- QLibrary(const QString &fileName, QObject *parent = Q_NULLPTR)
- QLibrary(const QString &fileName, int verNum, QObject *parent = Q_NULLPTR)
- QLibrary(const QString &fileName, const QString &version, QObject *parent = Q_NULLPTR)
- ~QLibrary()
- QString errorString() const
- QString fileName() const
- bool isLoaded() const
- bool load()
- LoadHints loadHints() const
- QFunctionPointer resolve(const char *symbol)
- void setFileName(const QString &fileName)
- void setFileNameAndVersion(const QString &fileName, int versionNumber)
- void setFileNameAndVersion(const QString &fileName, const QString &version)
- void setLoadHints(LoadHints hints)
- bool unload()
注意load用完了记着unload,还可以做version版本判断,其他的不说了,直接看简单范例。
3.2. 范例
不需要吧dll文件放到工程目录就行,因为编译的时候不会访问它,只需要放到运行目录即可
- #include <QCoreApplication>
- #include <QString>
- #include <QDebug>
- #include <QLibrary>
- typedef int (*myfun)(int, int);//定义函数格式
- int main(int argc, char *argv[]) {
- QCoreApplication a(argc, argv);
- QLibrary test_dll("library.dll");//加载dll
- if(test_dll.load()) {//判断是否加载成功
- myfun fun1 = (myfun)test_dll.resolve("sum");//获取dll的函数
- if (fun1) {//判断是否获取到此函数
- double result;
- result=fun1(1,2);//和正常调用函数一样了
- qDebug()<<QString(QStringLiteral("load ok, result:"))+
- QString::number(result);
- }
- else {
- //函数解析失败
- qDebug()<<QStringLiteral("dll function load error");
- }
- }
- else {
- qDebug()<<QStringLiteral("dll load error");//dll文件加载失败
- }
- return 0;
- }
范例很简单,然后运行就会发现给出的结果是:dll function load error
此时不要盲目的去找检查typedef 的错误,其实这个程序没错,错的是之前的dll项目。
因为c++为了适应函数重载,对于函数名称在编译过程中会做一定的修改,所以此时找sum肯定找不到,应该修改动态库的项目文件,把头文件改成:
- #ifndef LIBRARY_H
- #define LIBRARY_H
- #include <QtCore/qglobal.h>
- #if defined(LIBRARY_LIBRARY)
- # define LIBRARYSHARED_EXPORT Q_DECL_EXPORT
- #else
- # define LIBRARYSHARED_EXPORT Q_DECL_IMPORT
- #endif
- class LIBRARYSHARED_EXPORT Library {
- public:
- Library();
- int sum(int a, int b);
- };
- extern "C" int LIBRARYSHARED_EXPORT sum(int a, int b);
- #endif // LIBRARY_H
extern “C” 包含双重含义,从字面上即可得到:首先,被它修饰的目标是“extern”的;其次,被它修饰的目标是“C”的。让我们来详细解读这两重含义。
被extern “C”限定的函数或变量是extern类型的:extern是C/C++语言中表明函数和全局变量作用范围(可见性)的关键字,该关键字告诉编译器,其声明的函数和变量可以在本模块或其它模块中使用。同时”C”又告诉编译器以C语言方式编译和连接。
把新生成的文件拷贝到运行目录即可得到”load ok, result:3″
3.3. 比较extern”C”的dll与原始dll的差别
用depends工具查看dll文件,我把新的命名为library.dll旧的命名为library2.dll看图对比即可:
转载请以链接形式标明本文标题和地址:Techie亮博客 » Qt动态连接库/静态连接库创建与使用,QLibrary动态加载库
Qt动态连接库/静态连接库创建与使用,QLibrary动态加载库的更多相关文章
- Android 图片加载库Glide 实战(二),占位符,缓存,转换自签名高级实战
http://blog.csdn.net/sk719887916/article/details/40073747 请尊重原创 : skay <Android 图片加载库Glide 实战(一), ...
- Google推荐的图片加载库Glide介绍
英文原文 Introduction to Glide, Image Loader Library for Android, recommended by Google 译文首发 http://jco ...
- fackbook的Fresco (FaceBook推出的Android图片加载库-Fresco)
[Android开发经验]FaceBook推出的Android图片加载库-Fresco 欢迎关注ndroid-tech-frontier开源项目,定期翻译国外Android优质的技术.开源库.软件 ...
- Fresco-FaceBook推出的Android图片加载库
在Android设备上面,快速高效的显示图片是极为重要的.过去的几年里,我们在如何高效的存储图像这方面遇到了很多问题.图片太大,但是手机的内存却很小.每一个像素的R.G.B和alpha通道总共要占用4 ...
- Google图片加载库Glide的简单封装GlideUtils
Google图片加载库Glide的简单封装GlideUtils 因为项目里用的Glide的地方比较多,所有简单的封装了以下,其实也没什么,就是写了个工具类,但是还是要把基础说下 Glide的Githu ...
- Android图片加载库Fresco
在Android设备上面,快速高效的显示图片是极为重要的.过去的几年里,我们在如何高效的存储图像这方面遇到了很多问题.图片太大,但是手机的内存却很小.每一个像素的R.G.B和alpha通道总共要占用4 ...
- FaceBook推出的Android图片加载库-Fresco
FaceBook推出的Android图片加载库-Fresco 原文链接:Introducing Fresco: A new image library for Android 译者 : ZhaoKai ...
- Google推荐的图片加载库Glide
英文原文 Introduction to Glide, Image Loader Library for Android, recommended by Google 首发地址 http://jco ...
- Android图片加载库的理解
前言 这是“基础自测”系列的第三篇文章,以Android开发需要熟悉的20个技术点为切入点,本篇重点讲讲Android中的ImageLoader这个库的一些理解,在Android上最让人头疼是 ...
随机推荐
- Linux使用scp命令进行文件远程拷贝详解
前言 scp是 secure copy的缩写, scp是Linux系统下基于ssh登陆进行安全的远程文件拷贝命令.Linux的scp命令可以在Linux服务器之间复制文件和目录. 使用语法: scp ...
- 基于Doxygen_C语言代码文档一键生成的记录与规范(嵌入式适用)
下位机代码格式规范整合记录 注册 doxygen 账号获取doxygen 的 *.exe 执行文件 https://pan.baidu.com/s/1MF5v-Ts80BysmZtXSqONmg 提取 ...
- OpenStack部署博客推荐
OpenStack部署推荐博客 shhnwangjian https://www.cnblogs.com/shhnwangjian/category/942049.html(推荐) 点评: 1.实现过 ...
- kaggle之数据分析从业者用户画像分析
数据为kaggle社区发布的数据分析从业者问卷调查分析报告,其中涵盖了关于该行业不同维度的问题及调查结果.本文的目的为提取有用的数据,进行描述性展示.帮助新从业的人员更全方位地了解这个行业. 参考学习 ...
- Spring事务控制
我们在实际业务场景中,经常会遇到数据频繁修改读取的问题.在同一时刻,不同的业务逻辑对同一个表数据进行修改,这种冲突很可能造成数据不可挽回的错乱,所以我们需要用事务来对数据进行管理. 1. 到底什么是事 ...
- 20155202张旭 2016-2017-2 《Java程序设计》第2周学习总结
20155202张旭 2016-2017-2 <Java程序设计>第2周学习总结 教材学习内容总结 第一,二章知识小节: git log 命令来查看 :提交历史 查看当前所处位置: pwd ...
- 2017-2018-1 20155320 《信息安全系统设计基础》第四周学习总结(课堂实践补交+myhead与mytail加分项目)
2017-2018-1 20155320 <信息安全系统设计基础>第四周学习总结(课堂实践补交+myhead与mytail实现) 课堂实践内容 1 参考教材第十章内容 2 用Linux I ...
- day5 页面布局
1.主站 <div class='pg-header'> <div style='width:980px;margin:0 auto;'> 内容自动居中 </div> ...
- 1. oracle12C的安装
官方安装文档:https://docs.oracle.com/database/121/LTDQI/toc.htm#BHCCADGD 1.软件准备 oracle12c.zip 安装包 VMware 虚 ...
- day2 Ubuntu配置源
1.寻找国内镜像源 https://mirrors.tuna.tsinghua.edu.cn/help/ubuntu/ 2.配置source list源 sources.list系统自带的,源是来U ...