zoukankan      html  css  js  c++  java
  • 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文件:

    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动态加载库

  • 相关阅读:
    How to build Linux system from kernel to UI layer
    Writing USB driver for Android
    Xposed Framework for Android 8.x Oreo is released (in beta)
    Linux Smartphone Operating Systems You Can Install Today
    Librem 5 Leads New Wave of Open Source Mobile Linux Contenders
    GUADEC: porting GNOME to Android
    Librem 5 – A Security and Privacy Focused Phone
    GNOME and KDE Join Librem 5 Linux Smartphone Party
    Purism计划推出安全开源的Linux Librem 5智能手机
    国产系统之殇:你知道的这些系统都是国外的
  • 原文地址:https://www.cnblogs.com/techiel/p/8035014.html
Copyright © 2011-2022 走看看