關於Qt編譯庫(1):在子項目中編譯動態庫並且使用

本文演示了將一個自己編寫的類(SalesData)編譯爲動態庫或者靜態庫,並且新建的項目中使用該庫。
對於小白用戶,自己查了網上一些資料,進行了摸索,並將過程記錄下來,供他人蔘考。

1、本文主要說明了linux下的使用,windows亦可參考。
2、注意本文中使用的是子項目。普通項目的使用方法與本文相同。
項目名字爲sub,包含兩個子項目,window爲app,datafile爲lib。在window中要使用生成的lib庫文件。
在這裏插入圖片描述

1.編譯爲庫

1.1利用Qt庫模板

在Qt Creator中新建子項目,在其他項目——子目錄項目。
在這裏插入圖片描述

在這裏插入圖片描述

添加子項目,項目名字爲window。這個是我們的界面的項目。
添加子項目,選擇Library——C++庫在這裏插入圖片描述
選擇共享庫。如果生成靜態庫,則選擇靜態鏈接庫。
在這裏插入圖片描述
後續需要輸入類名,例如類名爲SalesData,這個是《C++ primer》這本書中經常使用的類。。。一直點下一步,最後會生成一個cpp和h文件。
在cpp文件和h文件中進行編寫,完畢後點擊“構建”按鈕,會生成庫文件。

1.2 自己修改pro文件生成

上述這種方法,是生成cpp和h文件,然後在裏邊修改。如果我們已經有了庫源文件,可以把之前默認生成的cpp和h刪掉,把我們自己的庫文件添加進去。當然有些繁瑣,實際上我們可以自己動手來配置庫項目。
我們選擇建立一個空的項目。選擇Empty qmake Project。
在這裏插入圖片描述
輸入子項目的名字datafile。會產生一個名爲datafile的文件夾以及一個同名的pro文件。
一直點下一步,最後會出來一個提示,說打開項目失敗。本來到目前爲止項目就是空的,不必理會。
在這裏插入圖片描述

1、建立一個空的Empty qmake Project。名字爲datafile,生成一個項目文件夾以及項目pro文件。會在我們的sub.pro中自動在SUBDIRS中加上內容。

注意linux上邊似乎SUBDIRS中的順序有要求。所以最好先寫庫項目,再寫app項目。
或者加上如下:

window.depends = datafile

在這裏插入圖片描述

2、加入已有的cpp和h文件。pro文件會自動增加SOURCES和HEADERS內容。
3、在pro文件中加入我們自己的東西。重要的是TEMPLATE設置。

在pro文件中將TEMPLATE = app改爲lib。表明我們這個是生成庫的項目。
使用lib模板時,可以將以下選項添加到CONFIG變量中,以確定所構建的庫的類型。
dll: 該庫是一個共享庫(dll)。
staticlib或者static: 該庫是一個靜態庫。
plugin: 該庫是一個插件。
我試了一下,如果沒不設置CONFIG中的庫類型時,自動生成的爲動態庫。

4、其他設置。我們修改DESTDIR,就是設置生成的文件的位置,表明我們生成到lib這個目錄下。另外還可以修改庫文件名字等。

5、添加庫的頭文件和源文件。
在這裏插入圖片描述
點擊構建,即可生成庫文件。

1.3 生成結果

以下是對生成生成文件後綴名的說明。這只是泛泛而談,實際發現跟編譯器有關。比如我在windows系統上用MinGW,可能靜態庫還是a後綴。

文件 靜態庫 動態庫 目標文件
LINUX a so o
WINDOWS lib dll obj

在windowd+MinGW編譯
這個SalesData.dll就是生成的動態鏈接庫。
在這裏插入圖片描述 在這裏插入圖片描述

在linux下生成結果
以so結尾的就是動態鏈接庫。生成了一個動態鏈接庫文件和3個軟鏈接。(不知爲什麼會這樣,但我試過把軟連接刪掉後是找不到庫文件的。)
在這裏插入圖片描述

2.使用庫

2.1 如何使用庫

調用動態庫必要條件:定義動態庫的頭文件 和 動態庫文件

我們以linux系統爲例說明。

在另一個子項目window中,調用第一節中我們生成的動態庫。

1、指定庫文件路徑和庫文件名字。
在這裏插入圖片描述
注意大寫的-L後接庫所在的路徑,小寫的-l後接庫名,庫名不需加lib前綴和so後綴。

設置LIBS其實說穿了很簡單,然後告訴工程,你的庫文件放到哪裏了,叫什麼名字。

2、設置庫頭文件搜索路徑。如上圖的INCLUDEPATH。就是說頭文件在什麼地方。就會到這個地方搜索頭文件。當然也可以不設該變量,而在用到的文件中用#include包含所在路徑以及頭文件名字,但是路徑太長時,#include這句話就會很長。

3、在使用該庫的文件中用#include包含頭文件,由於上邊已經設置過了INCLUDEPATH變量,所以直接寫頭文件名字就能搜索到。

#include "salesdata.h"

2.2 庫文件修改

如果靜態庫和動態庫進行了修改,庫都會重新編譯。但使用上有所不同。

對於動態庫,使用庫的代碼生成程序後,能夠正確鏈接到修改之後的庫。

對於靜態庫,由於使用庫的代碼沒有變化,所以使用庫的代碼不會重新編譯,因此該代碼生成的程序中仍然包含的是修改之前的靜態庫。要使用修改之後的靜態庫,就必須讓使用靜態庫的代碼重新編譯。例如在使用庫的代碼中隨便插入一個空白行等。

3.在運行目錄下運行

在生成的運行目錄下,執行./window可執行程序,會提示錯誤,找不到庫文件。

因爲linux會默認在幾個路徑中搜索庫文件,動態庫的搜索路徑搜索的先後順序是:

1.編譯目標代碼時指定的動態庫搜索路徑;通過gcc 的參數”-Wl,-rpath,”指定;
2.環境變量LD_LIBRARY_PATH指定的動態庫搜索路徑;
3.配置文件/etc/ld.so.conf中指定的動態庫搜索路徑;
4.默認的動態庫搜索路徑/lib;
5.默認的動態庫搜索路徑/usr/lib。

我們使用方法2,如下:
1、我們將datafile下的lib文件夾拷貝到此處,然後執行如下,就是將該目錄添加到環境變量中。然後再執行./window就可以執行了。注意每次開機都需要執行該export命令。

export LD_LIBRARY_PATH=$LD_LIBRARY_PATH:./lib/

2、爲了以後使用方便,可以編寫腳本,以後執行該腳本,就不用每次開機都執行export了。

#!/bin/bash
export LD_LIBRARY_PATH=$LD_LIBRARY_PATH:./lib/
./window

4.注意事項

4.1 子項目時的編譯順序

在這裏插入圖片描述
在linux上,似乎會按照SUBDIRS指定的順序編譯,可能編譯window項目時,datafile庫還沒有生成所以會報錯。所以最好把庫項目放在前邊,或者加上如下:

window.depends = datafile

但是在windows系統+minGW編譯時,順序打亂時也能正常編譯。

4.2 關於install操作

在編譯或者運行時,可以指定make install用來安裝文件。
但是注意如果用本文1.1章節中的動態庫模板,會生成如下指令:

unix {
    target.path = /usr/lib
    INSTALLS += target
}

企圖把生成的庫文件拷到/usr/lib/目錄下。但是這是需要權限的,所以在install時總是會出現拷貝時沒有權限錯誤。

本來我是用install安裝其他東西,結果總是提示拷貝lib沒有權限,我尋思我也沒考到/usr/lib目錄啊,找了好久才發現是使用動態庫模板自動加上類的這幾行。所以刪掉之後就正常了。
但是如何設置才能修改權限?尚不清楚。

另外我們也可以利用install來自動把datafile/lib庫文件拷到可執行程序所在的目錄,便於打包發佈等。

4.3 異常

使用我在qmake中將目錄保存爲變量,後來修改了目錄結構,但是變量沒有對應修改,後來編譯的時候沒有錯誤,但是運行的時候程序直接退出了。這個地方要注意一下。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章