QtCreator中使用鏈接庫


說明

之前討論的DLL的靜態鏈接和動態連接都是基於 MSVC 編譯器,但是 MinGW 似乎有另外一套類似但是不相同的機制。下文均在 windows 下使用 Qt Creator 中使用 MinGW 進行說明。

我們在新建庫項目的時候有三種選項,如圖所示:

三種類型分別是:共享庫、靜態鏈接庫和Qt插件,之間區別以及和 MSVC 的庫區別如下:

  1. 項目會根據類型不同生成 .dll 和 .a文件,這里的 .a 即類似 .lib,但是又不完全相同;
  2. 共享庫 類似 msvc 的靜態鏈接,構建最終生成 .a(類似.lib) 和 .dll,客戶端編譯時需要頭文件和 .a,運行時需要 .dll;
  3. 靜態鏈接庫 則是另外一種新的機制,構建最終只生成 .a 文件,客戶端調用時需要 .a 文件,運行時則不需要任何庫文件,類似於客戶端在編譯時將庫包進了自己的exe中;
  4. Qt插件不再多說,參考Qt插件系統文章,就是一種動態加載DLL的方法,但是又把加載的細節隱藏了;

綜上所屬,MingW 下的鏈接庫相比於 MSVC,着實簡單了很多,把內部的很多復雜的細節隱藏在Qt的內部系統中,對使用者來說,更加方便。

鏈接庫的使用

下面就來簡單介紹一下這些庫的使用,Qt的插件不在討論之列,請參考Qt插件系統文章。介紹中會忽略一些不重要的細節,我們認為你應該對C++和Qt有一個較深的認識,若沒有,請自行去學習相關知識。同時,我們順帶簡單介紹一些 .pro 文件的配置。

共享庫

(1)創建共享庫

共享庫類似靜態鏈接,生成.a文件和.dll文件。

按照正常流程新建庫項目,類型選擇 動態庫,最終生成的項目列表中如下如所示:

可以看出,除了需要導出的類外,額外還有一個XXX_global.h的文件,文件代碼如下:

#ifndef FIRECONTROL_GLOBAL_H
#define FIRECONTROL_GLOBAL_H

#include <QtCore/qglobal.h>

#if defined(FIRECONTROL_LIBRARY)
#  define FIRECONTROLSHARED_EXPORT Q_DECL_EXPORT
#else
#  define FIRECONTROLSHARED_EXPORT Q_DECL_IMPORT
#endif

#endif // FIRECONTROL_GLOBAL_H

了解 MSVC 的dll導出的都能了解,這里其實是對 __declspec(dllexport)__declspec(dllimport) 進行一種巧妙的聲明,因為導出需要使用export,導入需要使用import,為了避免在庫和客戶端中重復地進行export和import的聲明,這里使用宏定義進行統一聲明,詳細說明可以參考DLL的導出和調用的文章。

在需要導出的類和方法前面使用 FIRECONTROLSHARED_EXPORT 聲明即可,客戶端調用時也需要將這個文件include進來。

當然,如果你對導出DLL的一個比較清晰的認識,也可以刪除這個文件,自己定義。

(2)pro文件

QT       -= gui

TARGET = FireControl
TEMPLATE = lib	#表示這是一個庫項目

DEFINES += FIRECONTROL_LIBRARY

SOURCES += FireControlManager.cpp

HEADERS += FireControlManager.h\
        firecontrol_global.h

unix {
    target.path = /usr/lib
    INSTALLS += target
}
#上面為創建時自動生成,以下為新增
DESTDIR = $$PWD/../SystemWindow/lib	#最終編譯文件的生成路徑,包括.a和.dll
DLLDESTDIR = $$PWD/../../../Service	#dll文件的生成路徑

(3)調用共享庫

在調用端右擊->添加庫,選擇生成 .a 文件,即可自動在 pro文件中添加加載設置。當然,也可以不適用GUI操作,直接修改pro文件以達到添加庫的目的。

我們希望調用端和庫項目分開構建,所以這里選擇外部庫

添加.a的庫文件和頭文件的包含目錄,並配置一些鏈接方法

調用設置完成后,pro文件如下:

QT       += core gui

greaterThan(QT_MAJOR_VERSION, 4): QT += widgets

TARGET = SystemWindow
TEMPLATE = app

SOURCES += main.cpp\
        MainBench.cpp

HEADERS  += MainBench.h

FORMS    += MainBench.ui

#以下即為自動生成的加載庫設置
win32:CONFIG(release, debug|release): LIBS += -L$$PWD/lib/ -lFireControl
else:win32:CONFIG(debug, debug|release): LIBS += -L$$PWD/lib/ -lFireControl
else:unix:!macx: LIBS += -L$$PWD/lib/ -lFireControl

INCLUDEPATH += $$PWD/../FireControl
DEPENDPATH += $$PWD/../FireControl
DESTDIR = $$PWD/../../../Service	#目標生成路徑

最后,可以在客戶端使用庫導出的類了,當然不要忘了添加頭文件。

靜態庫

(1)創建靜態庫

靜態最終只會生成 .a 文件。

創建庫項目時,選擇靜態庫,完成之后,項目目錄的內容和目錄中,除了沒有入口的main函數外,其他都和普通項目沒有什么區別,而真正的區別在於pro文件的配置中。

(2)pro文件

QT       -= gui

TARGET = untitled
TEMPLATE = lib		#表示這是一個庫項目
CONFIG += staticlib	#表示這是一個靜態庫

SOURCES += untitled.cpp

HEADERS += untitled.h
unix {
    target.path = /usr/lib
    INSTALLS += target
}
DESTDIR = $$PWD/../SystemWindow/lib #生成路徑

(3)調用靜態庫

調用方法和調用共享庫類似,這里不做贅述,最終實際運行時不需要dll文件

總結

共享庫和靜態庫各有各的優勢,從最簡單的層面上來看:

使用靜態庫可以將大項目區分開,即分模塊顯示項目,便於維護;

使用共項目也是如此,而且可以在不修改客戶端的情況下,修改庫內容的實現,只要接口不變,最終替換dll即可完成內容的改變。

但是看起來靜態庫有些雞肋,具體還有哪些好處,留待日后發現。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM