Qt动态连接库/静态连接库创建与使用,QLibrary动态加载库

版权声明:若无来源注明,Techie亮博客文章均为原创。 转载请以链接形式标明本文标题和地址:
本文标题:Qt动态连接库/静态连接库创建与使用,QLibrary动态加载库     本文地址:http://techieliang.com/2017/12/680/

文章目录

1. 动态连接库创建与使用

1.1. 项目创建

注意选择成shared library

此时新建的项目pro文件:

  1. QT -= gui
  2. TARGET = library
  3. TEMPLATE = lib
  4. DEFINES += LIBRARY_LIBRARY
  5. DEFINES += QT_DEPRECATED_WARNINGS
  6. SOURCES += \
  7. library.cpp
  8. HEADERS += \
  9. library.h
  10. unix {
  11. target.path = /usr/lib
  12. INSTALLS += target
  13. }

注意其Template为lib,且声明了一个LIBRARY_LIBRARY

对于global.h文件建议直接拷贝到library.h,这样发布的时候只需要给别人一个.h文件

library.h

  1. #ifndef LIBRARY_H
  2. #define LIBRARY_H
  3. #include <QtCore/qglobal.h>
  4. #if defined(LIBRARY_LIBRARY)
  5. # define LIBRARYSHARED_EXPORT Q_DECL_EXPORT
  6. #else
  7. # define LIBRARYSHARED_EXPORT Q_DECL_IMPORT
  8. #endif
  9. class LIBRARYSHARED_EXPORT Library {
  10. public:
  11. Library();
  12. int sum(int a, int b);
  13. };
  14. int LIBRARYSHARED_EXPORT sum(int a, int b);
  15. #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

  1. Library::Library() {
  2. }
  3. int Library::sum(int a, int b) {
  4. return a+b;
  5. }
  6. int sum(int a, int b) {
  7. return a+b;
  8. }

此时直接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文件:

  1. QT -= gui
  2. CONFIG += c++11 console
  3. CONFIG -= app_bundle
  4. DEFINES += QT_DEPRECATED_WARNINGS
  5. 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

  1. #include <QCoreApplication>
  2. #include <library.h>
  3. #include <QDebug>
  4. int main(int argc, char *argv[]) {
  5. QCoreApplication a(argc, argv);
  6. qDebug()<<sum(1,2);//测试c函数
  7. Library t;
  8. qDebug()<<t.sum(1,2);//测试类函数
  9. return 0;
  10. }

此时运行,可以生成成功,但是会报错,因为dll文件还需要拷贝到生成的exe文件目录,拷贝后再运行即可

2. 静态库创建及使用

2.1. 创建

见动态库第二图,创建时不要选择shared,选择静态连接库Statically Linked Library。

创建项目以后没有什么特色,不会有global.h文件也不会有一个export、import的定义,因为静态库不需要导入导出,生成库提供给使用者,使用者在编译时会将代码需要的代码编译到自己的项目中,不需要附带dll/lib等文件。

先看pro文件:

  1. QT -= gui
  2. TARGET = static_library
  3. TEMPLATE = lib
  4. CONFIG += staticlib
  5. SOURCES += \
  6. static_library.cpp
  7. HEADERS += \
  8. static_library.h
  9. unix {
  10. target.path = /usr/lib
  11. INSTALLS += target
  12. }

相比于动态链接库差异是增加了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文件:

  1. #include <QCoreApplication>
  2. #include <static_library.h>
  3. #include <QDebug>
  4. int main(int argc, char *argv[]) {
  5. QCoreApplication a(argc, argv);
  6. qDebug()<<sum(1,2);
  7. Static_library l;
  8. qDebug()<<l.sum(1,2);
  9. return 0;
  10. }

运行即可,这里就不需要吧.a文件复制到程序目录了,因为静态库编译的时候已经把需要的内容编译到exe程序了。

3. QLibrary动态加载动态库

3.1. 介绍

在动态库使用那里,直接编译运行会无法打开,把dll文件拷贝到运行目录才能打开程序,否则会提示缺少文件,然后就没有然后了。。。

不知道是否注意到有些程序是主动提示缺少文件错误的?会在程序运行到需要库文件时提示缺少此库,并且可以自定义提示内容,而不是用系统默认的错误提示,若想实现此功能需要动态加载。当然在库供应方只给了dll文件没给.h的时候也能使用,换句话说动态加载方式在编写项目时不需要.h文件,也不需要在pro文件增加“libs+=”

先看帮助文档:http://doc.qt.io/qt-5/qlibrary.html

接口很简单:

  1. QLibrary(QObject *parent = Q_NULLPTR)
  2. QLibrary(const QString &fileName, QObject *parent = Q_NULLPTR)
  3. QLibrary(const QString &fileName, int verNum, QObject *parent = Q_NULLPTR)
  4. QLibrary(const QString &fileName, const QString &version, QObject *parent = Q_NULLPTR)
  5. ~QLibrary()
  6. QString errorString() const
  7. QString fileName() const
  8. bool isLoaded() const
  9. bool load()
  10. LoadHints loadHints() const
  11. QFunctionPointer resolve(const char *symbol)
  12. void setFileName(const QString &fileName)
  13. void setFileNameAndVersion(const QString &fileName, int versionNumber)
  14. void setFileNameAndVersion(const QString &fileName, const QString &version)
  15. void setLoadHints(LoadHints hints)
  16. bool unload()

注意load用完了记着unload,还可以做version版本判断,其他的不说了,直接看简单范例。

3.2. 范例

不需要吧dll文件放到工程目录就行,因为编译的时候不会访问它,只需要放到运行目录即可

  1. #include <QCoreApplication>
  2. #include <QString>
  3. #include <QDebug>
  4. #include <QLibrary>
  5. typedef int (*myfun)(int, int);//定义函数格式
  6. int main(int argc, char *argv[]) {
  7. QCoreApplication a(argc, argv);
  8. QLibrary test_dll("library.dll");//加载dll
  9. if(test_dll.load()) {//判断是否加载成功
  10. myfun fun1 = (myfun)test_dll.resolve("sum");//获取dll的函数
  11. if (fun1) {//判断是否获取到此函数
  12. double result;
  13. result=fun1(1,2);//和正常调用函数一样了
  14. qDebug()<<QString(QStringLiteral("load ok, result:"))+
  15. QString::number(result);
  16. }
  17. else {
  18. //函数解析失败
  19. qDebug()<<QStringLiteral("dll function load error");
  20. }
  21. }
  22. else {
  23. qDebug()<<QStringLiteral("dll load error");//dll文件加载失败
  24. }
  25. return 0;
  26. }

范例很简单,然后运行就会发现给出的结果是:dll function load error

此时不要盲目的去找检查typedef 的错误,其实这个程序没错,错的是之前的dll项目。

因为c++为了适应函数重载,对于函数名称在编译过程中会做一定的修改,所以此时找sum肯定找不到,应该修改动态库的项目文件,把头文件改成:

  1. #ifndef LIBRARY_H
  2. #define LIBRARY_H
  3. #include <QtCore/qglobal.h>
  4. #if defined(LIBRARY_LIBRARY)
  5. # define LIBRARYSHARED_EXPORT Q_DECL_EXPORT
  6. #else
  7. # define LIBRARYSHARED_EXPORT Q_DECL_IMPORT
  8. #endif
  9. class LIBRARYSHARED_EXPORT Library {
  10. public:
  11. Library();
  12. int sum(int a, int b);
  13. };
  14. extern "C" int LIBRARYSHARED_EXPORT sum(int a, int b);
  15. #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动态加载库

时间: 2024-10-12 08:50:05

Qt动态连接库/静态连接库创建与使用,QLibrary动态加载库的相关文章

AutoSharedLibrary -- 基于模板元编程技术的跨平台C++动态链接加载库

基于模板元编程技术的跨平台C++动态链接加载库.通过模板技术,使用者仅需通过简单的宏,即可使编译器在编译期自动生成加载动态链接库导出符号的代码,无任何额外的运行时开销. ASL_LIBRARY_BEGIN(TestLib) ASL_SYMBOL(Proc_test1, test1, false) ASL_SYMBOL(Proc_test2, test2, true) ASL_LIBRARY_END() TestLib theLib; try { theLib.Load("./1.so"

Android图片加载库的封装实战之路

前言 主流图片加载库的对比 Android-Universal-Image-Loader Picasso Glide Fresco 按需选择图片加载库 如何更好地封装图片加载库 为什么要封装 使用策略模式封装图片加载策略 源码地址 部分参考链接 前言 图片加载是Android开发中最最基础的功能,为了降低开发周期和难度,我们经常会选用一些图片加载的开源库 选取第三方SDK需要谨慎 二次封装 主流图片加载库的对比 共同点 使用简单:一句话实现图片的获取和显示 可配置性高:可配置各种解码.缓存.下载

Google推荐的图片加载库Glide介绍

目录(?)[+] 英文原文 Introduction to Glide, Image Loader Library for Android, recommended by Google 首发地址  http://jcodecraeer.com/a/anzhuokaifa/androidkaifa/2015/0327/2650.html 在泰国举行的谷歌开发者论坛上,谷歌为我们介绍了一个名叫 Glide 的图片加载库,作者是bumptech.这个库被广泛的运用在google的开源项目中,包括201

【Android开发经验】FaceBook推出的Android图片加载库-Fresco

欢迎关注ndroid-tech-frontier开源项目,定期翻译国外Android优质的技术.开源库.软件架构设计.测试等文章 原文链接:Introducing Fresco: A new image library for Android 译者 : ZhaoKaiQiang 校对者: Chaossss 校对者: bboyfeiyu 校对者: BillionWang 状态 : 完成 在Android设备上面,快速高效的显示图片是极为重要的.过去的几年里,我们在如何高效的存储图像这方面遇到了很多

ym——Android图片加载库Glide

转载请注明本文出自Cym的博客(http://blog.csdn.net/cym492224103),谢谢支持! 前言 在泰国举行的谷歌开发者论坛上,谷歌为我们介绍了一个名叫 Glide 的图片加载库,作者是bumptech.这个库被广泛的运用在google的开源项目中,包括2014年google I/O大会上发布的官方app. 它的成功让我非常感兴趣.我花了一整晚的时间把玩,决定分享一些自己的经验.在开始之前我想说,Glide和Picasso有90%的相似度,准确的说,就是Picasso的克隆

Fresco-FaceBook推出的Android图片加载库

在Android设备上面,快速高效的显示图片是极为重要的.过去的几年里,我们在如何高效的存储图像这方面遇到了很多问题.图片太大,但是手机的内存却很小.每一个像素的R.G.B和alpha通道总共要占用4byte的空间.如果手机的屏幕是480*800,那么一张屏幕大小的图片就要占用1.5M的内存.手机的内存通常很小,特别是Android设备还要给各个应用分配内存.在某些设备上,分给Facebook App的内存仅仅有16MB.一张图片就要占据其内存的十分之一. 当你的App内存溢出会发生什么呢?它当

Fresco介绍 - 一个新的android图片加载库

在Android设备上面,快速高效的显示图片是极为重要的.过去的几年里,我们在如何高效的存储图像这方面遇到了很多问题.图片太大,但是手机的内存却很小.每一个像素的R.G.B和alpha通道总共要占用4byte的空间.如果手机的屏幕是480*800,那么一张屏幕大小的图片就要占用1.5M的内存.手机的内存通常很小,特别是Android设备还要给各个应用分配内存.在某些设备上,分给Facebook App的内存仅仅有16MB.一张图片就要占据其内存的十分之一. 当你的App内存溢出会发生什么呢?它当

网络请求库和图片加载库

网络请求库 概述:所有网络库的原理是: 网络请求一般是基于HttpURLConnection和HttpClient进行封装的,也有自己编写Socket实现的,比如ion和OkHttp:请求的执行一般是通过线程池来管理,异步请求得到结果,则通过回调接口接收:并且一般接收结果的回调都通过Handler去在主线程执行 Ion的使用 详情查看Github主页https://github.com/koush/ion 介绍: 它支持网络请求和进行图片加载的双重功能 拥有链式api风格(Fluent API)

Android图片加载库Picasso源码分析

图片加载在Android开发中是非常重要,好的图片加载库也比比皆是.ImageLoader.Picasso.Glide.Fresco均是优秀的图片加载库. 以上提到的几种图片加载库各有特色.用法与比较,网上已经很多了. 出于学习的角度,个人认为从Picasso入手较好.代码量小,同时API优美,很适合我们学习. 今天笔者就Picasso的源码进行分析,抛出一些图片加载的技术细节供园友参考. PS:建议园友先大致看一下源码. 我们对图片加载的要求 1.加载速度要快 2.资源消耗要低 3.加载图片不