Qt 之建立並使用靜態連結庫
簡述
摘自維基百科:
靜態連結庫(Statically-linked library),或稱靜態庫,是一個外部函式與變數的集合體。靜態庫的檔案內容,通常包含一堆程式設計師自定的變數與函式,其內容不像動態連結庫那麼複雜,在編譯期間由編譯器與聯結器將它整合至應用程式內,並製作成目標檔案以及可以獨立運作的可執行檔案。而這個可執行檔案與編譯可執行檔案的程式,都是一種程式的靜態建立(static build)。以過去的觀點來說,庫只能算是靜態(static)型別。
|
建立靜態連結庫
建立靜態連結庫的步驟和共享庫基本相同,唯一的區別是【型別】需要選擇“靜態連結庫”:
這裡,將專案名稱命名為 StaticLib
專案檔案
在專案建立完成之後,Qt Creator 會自動生成相關的檔案,目錄結構如下:
與共享庫不同,這裡並沒有出現了一個名為 {projectName}_global.h
的檔案,Why?這是因為靜態連結庫將被內建到應用程式中,所以無需在 .h
檔案中設定匯出和匯入符號的特殊功能。
檢視 .pro
,並對其稍作修改:
TARGET = StaticLib
# 新增部分
CONFIG += debug_and_release
CONFIG(debug, debug|release) {
unix: TARGET = $$join(TARGET,,,_debug)
else: TARGET = $$join(TARGET,,,d)
}
TEMPLATE = lib
CONFIG += staticlib
與共享庫的另一個不同之處在於:這裡多了一個 CONFIG
選項,其值為 staticlib
。沒錯,這正是要告訴 qmake,我們需要生成的是一個靜態連結庫。
生成靜態連結庫
可以看到,生成的庫中只有一個簡單的類定義,對其稍作修改。
staticlib.h
內容如下:
#ifndef STATICLIB_H
#define STATICLIB_H
int subtract(int x, int y);
class StaticLib
{
public :
StaticLib();
int add(int x, int y);
};
#endif // STATICLIB_H
staticlib.cpp
內容如下:
#include "staticlib.h"
int subtract(int x, int y)
{
return x - y;
}
StaticLib::StaticLib()
{
}
int StaticLib::add(int x, int y)
{
return x + y;
}
構建(不執行)專案,會生成相應的 .lib
檔案。
注意: Debug
版本為 StaticLibd.lib
(帶 d),Release
版本為 StaticLib.lib
(不帶 d)。
使用靜態連結庫
建立一個簡單的客戶端 - Qt Console Application,並使用靜態連結庫,效果如下:
專案建立成功後,將剛才生成的靜態連結庫組織成以下結構:
- StaticLibClient/
- StaticLibClient.pro
- main.cpp
- 3rdparty/
- StaticLib/
- include/
- staticlib.h
- lib/
- StaticLibd.lib
- StaticLib.lib
靜態連結庫的使用方式和共享庫類似,不同的是這裡將【連結】選擇為“靜態”:
這時,.pro
中會自動新增以下程式碼:
win32:CONFIG(release, debug|release): LIBS += -L$$PWD/3rdparty/StaticLib/lib/ -lStaticLib
else:win32:CONFIG(debug, debug|release): LIBS += -L$$PWD/3rdparty/StaticLib/lib/ -lStaticLibd
INCLUDEPATH += $$PWD/3rdparty/StaticLib/include
DEPENDPATH += $$PWD/3rdparty/StaticLib/include
win32-g++:CONFIG(release, debug|release): PRE_TARGETDEPS += $$PWD/3rdparty/StaticLib/lib/libStaticLib.a
else:win32-g++:CONFIG(debug, debug|release): PRE_TARGETDEPS += $$PWD/3rdparty/StaticLib/lib/libStaticLibd.a
else:win32:!win32-g++:CONFIG(release, debug|release): PRE_TARGETDEPS += $$PWD/3rdparty/StaticLib/lib/StaticLib.lib
else:win32:!win32-g++:CONFIG(debug, debug|release): PRE_TARGETDEPS += $$PWD/3rdparty/StaticLib/lib/StaticLibd.lib
類似於為共享庫載入所做的工作,需要將 INCLUDEPATH
指向標頭檔案所在目錄,並將 LIBS
變數指向 .lib
檔案。但是,這裡多了一個變數 - PRE_TARGETDEPS
,它用於列出目標所依賴的庫,尤其是對於顯式列出相關的靜態庫很有用。
建議: 如果使用靜態連結庫,應該始終同時使用 LIBS
和 PRE_TARGETDEPS
。
開始測試,main.cpp
內容如下:
#include <QCoreApplication>
#include <qDebug>
#include "staticlib.h"
int main(int argc, char *argv[])
{
QCoreApplication a(argc, argv);
// 測試庫
StaticLib lib;
qDebug() << lib.add(2, 3);
qDebug() << subtract(5, 2);
return a.exec();
}
OK,執行程式,效果如上所示。
選擇哪種方式
目前為止,介紹了兩種庫 - 共享庫和靜態連結庫,但是分享了三種使用方式。
到底如何選擇?這完全取決於你的需要。
- 在建立共享庫時,需要將其部署到應用程式中。從好的方面來說,與共享庫相關聯的應用程式和庫很小。
- 是否要使用
QLibrary
在執行時載入.dll
,取決於是否訪問了.h
標頭檔案和.lib
檔案。如果無法訪問這些檔案,那麼QLibrary
是另一種選擇。 - 靜態連結會生成一個獨立的可執行檔案,這樣做的好處是隻需要部署幾個檔案,缺點是可執行檔案很大。