Qt動態鏈接庫/靜態鏈接庫建立與使用,QLibrary動態加載庫

版權聲明:若無來源註明, Techie亮博客文章均爲原創。 轉載請以連接形式標明本文標題和地址:
本文標題:Qt動態鏈接庫/靜態鏈接庫建立與使用,QLibrary動態加載庫     本文地址: https://www.techieliang.com/2017/12/680/

1. 動態鏈接庫建立與使用

1.1. 項目建立

注意選擇成shared libraryhtml

此時新建的項目pro文件:linux

  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_LIBRARYc++

對於global.h文件建議直接拷貝到library.h,這樣發佈的時候只須要給別人一個.h文件windows

library.happ

  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)ui

注意生成庫也區分debug和release,debug的庫內帶有調試代碼,通常debug的庫文件名最後是d也就是spa

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動態加載庫

相關文章
相關標籤/搜索