1. 動態鏈接庫建立與使用
1.1. 項目建立
![](http://static.javashuo.com/static/loading.gif)
注意選擇成shared libraryhtml
![](http://static.javashuo.com/static/loading.gif)
此時新建的項目pro文件:linux
- 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_LIBRARYc++
對於global.h文件建議直接拷貝到library.h,這樣發佈的時候只須要給別人一個.h文件windows
library.happ
- #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)ui
注意生成庫也區分debug和release,debug的庫內帶有調試代碼,通常debug的庫文件名最後是d也就是spa
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看圖對比便可:
![](http://static.javashuo.com/static/loading.gif)
![](http://static.javashuo.com/static/loading.gif)
轉載請以連接形式標明本文標題和地址:Techie亮博客 » Qt動態鏈接庫/靜態鏈接庫建立與使用,QLibrary動態加載庫