程序師世界是廣大編程愛好者互助、分享、學習的平台,程序師世界有你更精彩!
首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫知識
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
 程式師世界 >> 編程語言 >> C語言 >> 關於C語言 >> Qt學習之路(60): 創建shared library

Qt學習之路(60): 創建shared library

編輯:關於C語言

前段時間說了Qt一些類庫的使用,今天來換一下口味,來看一下程序設計的問題。今天來說的是關於共享庫 shared library。

如果你打開一些 Windows 應用程序的目錄,你會發現有很多程序的 exe 文件都很小,大約幾百K 的樣子,並且目錄中不僅僅只有一個 exe 文件,還包含著一大堆 dll 文件。這些 dll 其實就是一些共享庫,所謂共享庫,其實就是一些動態鏈接庫,能夠由程序在運行時進行動態加載的庫。既然說是共享,那就是說,這些庫不僅僅自己的程序可以使用,並且其他程序也可以使用,例如某些通用算法。如果你發布一下自己編寫的 Qt 程序,也會看到很多系統的共享庫,就是那些 QtGui.dll 之類的東西。或許你會說,我寫的程序沒有同其他應用共享的庫,就不需要這些了吧!其實不然。因為共享庫的一個好處是可以動態加載,也就是說,如果你需要升級程序,那麼就要簡單的替換掉這個 dll 就好了,不需要要求用戶重新安裝全部文件。當然,這些 dll 也是有缺點的:動態加載的東西肯定會比靜態編譯的東西效率低一些。不過在現在的硬件環境下,這點性能損失已經可以忽略不計了。

今天我們要說的就是如何用 Qt 創建共享庫代碼。

我們還是使用 QtCreator。在創建工程的時候,我們選擇下面的 C++ Library 一項,然後點擊 OK。

在接下來的對話框中,有一個下拉列表,分別是 Shared Library共享庫),Statically Linked Library靜態鏈接庫)和 Qt 4 PluginQt 4 插件)。我們選擇第一個共享庫,後面的步驟中會要求選擇加入哪幾個 Qt 模塊,和前面一樣,選擇自己需要的部分,最後完成工程的創建。

我們會看到 QtCreator 已經幫我們創建好了一些文件。其中有一個 {projectName}_global.h 的文件是 QtCreator 替我們創建的。下面我們就從這個 {projectName}_global.h 開始:

  1. #ifndef LIB_GLOBAL_H  
  2. #define LIB_GLOBAL_H  
  3.  
  4. #include <QtCore/qglobal.h>  
  5.  
  6. #if defined(LIB_LIBRARY)  
  7. #  define LIBSHARED_EXPORT Q_DECL_EXPORT  
  8. #else  
  9. #  define LIBSHARED_EXPORT Q_DECL_IMPORT  
  10. #endif  
  11.  
  12. #endif // LIB_GLOBAL_H  

這個文件中只是定義了兩個宏 LIBSHARED_EXPORT,注意這裡的 LIB 就是我的工程名字。如果定義了 LIB_LIBRARY,LIBSHARED_EXPORT 定義為 Q_DECL_EXPORT,否則定義為 Q_DECL_IMPORT。看這個名字,就知道這就是把對象導出的語句了。下面我們來編寫一個窗口如果你希望這麼做,不要忘記在創建工程時勾選 QtGui 模塊,默認是不勾選的):

lib.h

  1. #ifndef LIB_H  
  2. #define LIB_H  
  3.  
  4. #include <QMainWindow>  
  5.  
  6. #include "lib_global.h"  
  7.  
  8. class LIBSHARED_EXPORT MainWindow : public QMainWindow {  
  9. public:  
  10.     MainWindow(QWidget *parent = 0);  
  11. };  
  12.  
  13. #endif // LIB_H 

lib.cpp

  1. #include "lib.h"  
  2.  
  3. MainWindow::MainWindow(QWidget *parent)  
  4.     : QMainWindow(parent)  
  5. {  
  6. }  

代碼很簡單,就是創建一個 MainWindow。同前面的代碼唯一不同的是,在頭文件中,使用了 LIBSHARED_EXPORT 這個宏。你可以簡單的把它理解成,我需要把這個類 MainWindow 導出。所謂導出,就是將其編譯成一個 dll 文件之後,其他的類可以使用這個導出類。好了,下面和原來一樣,編譯一下這個工程。在 debug 文件夾下你得到的是一個 lib.dll 文件和 liblib.a。後者是 Linux 下使用的庫,這裡不再詳述。

好了,我們要去使用這個 dll 了。新建另外一個工程,需要吧 .pro 文件修改一下:

  1. TARGET = test  
  2. TEMPLATE = app  
  3.  
  4. SOURCES += main.cpp  
  5.  
  6. INCLUDEPATH += ../  
  7.  
  8. LIBS += ../debug/lib.dll 

首先,我們添加了 INCLUDEPATH 這一行。這一行就是為了讓我們的 test 項目可以找到 lib.h 和 lib_global.h 這兩個文件,你需要把這裡的路徑替換成符合你的工程的路徑。LIBS 這一行則需要告訴編譯器注意,這裡是編譯器!)到哪裡去找到這個 dll 文件。然後我們編寫 main.cpp:

  1. #include <QtGui/QApplication>  
  2. #include "lib.h"  
  3.  
  4. int main(int argc, char *argv[])  
  5. {  
  6.     QApplication a(argc, argv);  
  7.     MainWindow w;  
  8.     w.show();  
  9.     return a.exec();  
  10. }  

注意,我們使用了 lib.h,但是這個文件並沒有在 HEADERS 裡面聲明,Qt 實際上就是從 INCLUDEPATH 這裡去找到這個文件。MainWindow 在新建的 test 工程中並沒有聲明,那麼它在哪裡呢?當然就是在我們編譯出來的 lib.dll 裡面啦!我們知道,在鏈接的時候編譯器需要找到實現入口,也就是必須定位到這個 dll,這就是由這個 LIBS 指定的地方。

最後編譯運行一下這個 exe 文件,怎麼樣?哦,如果你照我說的做了的話,你應該得到一個錯誤:找不到 lib.dll。怎麼會找不到呢?不是使用 LIBS 指定了嗎?請注意,我們強調了,這個指定是編譯期的。dll 是動態鏈接庫,也就是說,在 exe 運行的時候需要找到這個庫。運行時查找的順序是:當前路徑 -> 系統路徑(通常是 system32)。所以,要把我們先前生成的這個 lib.dll 復制到 exe 所在目錄,然後直接雙擊一下這個 exe 文件。一個窗口出來了!有什麼區別嗎?運行起來是沒有區別的,但是我們知道,這個窗口是在這個 dll 裡面實現的!我們想往窗口裡面加個按鈕?沒問題,那就加吧!加完之後重新編譯一個新的 dll,復制到 exe 文件夾覆蓋舊的,修改就完成啦!我們不需要修改這個 exe 了。

這個時候我們再來回憶一下,我們使用自己創建的 dll 的時候,是不是就和使用 QtGui.dll 一樣呢?只不過QtGui.dll 已經放在了庫目錄下, 不需要手動修改 .pro 文件添加 INCLUDEPATH 和 LIBS 罷了。

本文出自 “豆子空間” 博客,請務必保留此出處http://devbean.blog.51cto.com/448512/319479

  1. 上一頁:
  2. 下一頁:
Copyright © 程式師世界 All Rights Reserved