本文演示了將一個自己編寫的類(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中將目錄保存爲變量,後來修改了目錄結構,但是變量沒有對應修改,後來編譯的時候沒有錯誤,但是運行的時候程序直接退出了。這個地方要注意一下。