1. 靜態庫lib和動態dll的區別
1.1 項目類型
VS在建Win32項目時,有以下選項:
- windows應用程序
- 控制台應用程序
- DLL
- 靜態庫
最后兩個類型:DLL和靜態庫,這兩種項目類型是不可以單獨運行的,必須在Windows應用程序調用他們執行,是提供的庫函數而已。
1.2 兩種lib的區別:
(1)靜態庫(.lib)
函數和數據被編譯進一個二進制文件(通常擴展名為.LIB)。在使用靜態庫的情況下,在編譯鏈接可執行文件時,鏈接器從庫中復制這些函數和數據並把它們和應用程序的其他模塊組合起來創建最終的可執行文件(.EXE文件)。當發布產品時,只需要發布這個可執行文件,並不需要發布被使用的靜態庫。
(2)動態庫(.lib文件和.dll文件)
在使用動態庫的時候,編譯后往往提供兩個文件:一個引入庫(.lib)文件(也稱“導入庫文件”)和一個DLL(.dll)文件。當然到了后面會告訴你如果只提供一個DLL文件,使用顯示連接的方式也可以調用,只是稍加麻煩而已。
雖然引入庫的后綴名也是“lib”,但是,動態庫的引入庫文件和靜態庫文件有着本質的區別。對一個DLL文件來說,其引入庫文件(.lib)包含該DLL導出的函數和變量的符號名,而.dll文件包含該DLL實際的函數和數據。在使用動態庫的情況下,在編譯鏈接可執行文件時,只需要鏈接該DLL的引入庫文件,該DLL中的函數代碼和數據並不可復制到可執行文件,直到可執行程序運行時,才去加載所需的DLL,將該DLL映射到進程的地址空間中,然后訪問DLL中導出的函數。這時,在發布產品時,除了發布可執行文件以外,同時還需要發布該程序將要調用的動態鏈接庫。
只有當EXE程序確實要調用這些DLL模塊的情況下,系統才會將它們裝載到內存空間中。這種方式不僅減少了EXE文件的大小和對內存空間的需求,而且使這些DLL模塊可以同時被多個應用程序使用。如果DLL不在內存中,系統就將其加載到內存中。當鏈接Windows程序以產生一個可執行文件時,你必須鏈接由編程環境提供的專門的 “引入庫(import library)”。這些引入庫包含了動態鏈接庫名稱和所有Windows函數調用的引用信息。鏈接程序使用該信息在.EXE文件中構造一個表,當加載程序時,Windows使用它將調用轉換為Windows函數。
引入庫LIb和靜態庫Lib的區別:
引入庫和靜態庫的區別很大,他們實質是不一樣的東西。靜態庫本身就包含了實際執行代碼、符號表等等,而對於引入庫而言,其實際的執行代碼位於動態庫中,引入庫只包含了地址符號表等,確保程序找到對應函數的一些基本地址信息。但是引入庫文件的引入方式和靜態庫一樣,要在鏈接路徑上添加找到這些.lib的路徑。
1.3 動態庫(Lib和DLL)和靜態庫Lib的區別:
其實上面已經提到了區別,這里再總結一下:
(1)靜態鏈接庫與動態鏈接庫都是共享代碼的方式,如果采用靜態鏈接庫,lib 中的指令都全部被直接包含在最終生成的 EXE 文件中了,最終的可執行文件exe會比較大。但是若使用 DLL,該 DLL 不必被包含在最終 EXE 文件中,EXE 文件執行時可以“動態”地引用和卸載這個與 EXE 獨立的 DLL 文件。
(2)靜態鏈接庫和動態鏈接庫的另外一個區別在於靜態鏈接庫中不能再包含其他的動態鏈接庫或者靜態庫,而在動態鏈接庫中還可以再包含其他的動態或靜態鏈接 庫。靜態鏈接庫與靜態鏈接庫調用規則總體比較如下。
靜態鏈接庫運行之前就加載了,而且一直存在直到關閉程序,動態DLL實在運行時再加載,不用一直占內存,dll模塊內部更改了,是要替換Dll即可,方便維護。優點明顯,但是dll如果丟失或被誤刪,就無法運行了
2. 靜態庫lib和動態dll的使用
2. 1 動態dll的使用
動態鏈接庫的使用需要庫的開發者提供生成的.lib文件和.dll文件。或者只提供dll文件。使用時只能使用dll中導出的函數,未導出的函數只能在dll內部使用。Dll的調用有顯示連接和隱式連接兩種:隱式連接需要三個東西,分別是*.h頭文件,lib庫(動態的),DLL庫;顯示連接只需要.dll文件即可。
2.1.1 隱式連接
隱式鏈接需要三個東西,分別是*.h頭文件,lib庫(動態的),DLL庫,而這里的lib庫僅是編譯的時候用,運行時候不用,運行時只用Dll
2.1.1.1 添加Lib
方法1: 通過設置工程配置來添加lib庫.
A、添加工程的頭文件目錄:工程->屬性->配置屬性->c/c++->常規->附加包含目錄:加上頭文件存放目錄。添加頭文件參考2.2.1.2
B、添加文件引用的lib靜態庫路徑:工程->屬性->配置屬性->鏈接器->常規->附加庫目錄:加上lib文件存放目錄。
C 然后添加工程引用的lib文件名:工程->屬性->配置屬性->鏈接器->輸入->附加依賴項:加上lib文件名。
這種方法比較繁瑣,且不直觀,而且還可能要爭對debug版本和release版本作不同的配置,因為我們生成的兩個版本的庫可能放在不同的目錄中的.
方法2: 使用編譯語句:
#ifdef _DEBUG #pragma comment(lib,"..\\debug\\LedCtrlBoard.lib") #else #pragma comment(lib,"..\\release\\LedCtrlBoard.lib") #endif
這種方法直觀,方便,且可以按如上直接區分出Debug版本和Release版本的不同目錄.當然,通過宏,還可以區分更多版本.但是在指定目錄時,不小心容易出錯.
方法3: 直接添加庫文件到工程中.
就像你添加.h和.cpp文件一樣,把lib文件添加到工程文件列表中去.
VC中,切換到”解決方案視圖”—>選中要添加lib的工程–>點擊右鍵–>”添加”–>”現有項”–>選擇lib文件–>確定.
這個方法適用於在我的工程的debug版本和Release版本中都使用同一個lib庫文件時.這樣就省去了你1方法配置環境的繁瑣,也省去了方法2種語句的可能性錯誤發生。
2.1.1.2添加頭文件
在調用DLL中導出的函數之前要include對應的頭文件,可以寫絕對路徑,也可以拷貝到工程調用源文件的同一目錄下,也可以通過VS添加(include)頭文件目錄,VS中配置方法:
(1)VS項目->右擊屬性->配置屬性->VC++目錄->包含目錄
(2)VS項目->右擊屬性->配置屬性->C/C++->常規->附加包含目錄
2.1.1.3 添加dll
一般將dll拷貝到運行時目錄即可,與調用者exe文件在同一目錄,當然有其他方法添加環境變量PATH,
(1)VS項目->右擊屬性->配置屬性->VC++目錄->可執行目錄
(2)設定DLL目錄的位置,具體方法為:項目右擊->屬性 -> 配置屬性 -> 調試 ->工作目錄,在這里設置dll的路徑就可以了
注1:release版本和debug版本的區分,每種版本的設置都是獨立的,要分別設置
注2:單純添加lib目錄的方法有以下幾種方法
(1):把.lib文件放在當前使用它的工程目錄下;(如:.exe所在目錄,或者工程代碼所在的目錄)
(2):對某一個項目:項目”->“屬性”->“配置屬性”->“VC++目錄”->“常規”->“附加庫目錄”
(3):在vs中,“項目”->“屬性”->“配置屬性”->“鏈接器”->“常規”->“附加庫目錄”
(4):放在開發環境IDE的lib庫目錄下,例如:“C:\Program Files\Microsoft Visual Studio 8\VC\lib”,這是vs2005的vc開發的lib庫目錄。
注:在VS屬性中配置路徑時可以用絕對路徑,也可以用相對路徑,其中./表示當前目錄,而../表示上一級目錄
上面僅僅對單個項目有效,我們配置過opencv庫的都知道,有一種是全局配置lib和include頭文件,對所有的項目有效,以Debug版為例,步驟如下:
(1) 點擊“視圖”→“其他窗口”→“屬性管理器”
(2) 從左側項目中打開“Debug| Win32”→“Microsoft.Cpp.Win32.user”
(3) 雙擊“Microsoft.Cpp.Win32.user”,在彈出的窗口,點擊左側VC++目錄,編輯右側的可執行文件目錄、包含目錄與庫目錄,分別添加對應的路徑
(4) 附加依賴項,單擊“鏈接器”→“輸入”→“附加依賴項”,填入依賴項.lib后綴的文件名。
2.1.2 顯示連接
隱式鏈接雖然實現較簡單,但除了必須的.dll文件外還需要DLL的.h文件和.lib文件,在那些只提供.dll文件的場合就無法使用,而只能采用顯式鏈接的方式。這種方式通過調用API函數來完成對DLL的加載與卸載,能更加有效地使用內存,在編寫大型應用程序時往往采用此方式。這種方法編程具體實現步驟如下:
①使用Windows API函數Load Library或者MFC提供的AfxLoadLibrary將DLL模塊映像到進程的內存空間,對DLL模塊進行動態加載。
②使用GetProcAddress函數得到要調用DLL中的函數的指針。
③不用DLL時,用Free Library函數或者AfxFreeLibrary函數從進程的地址空間顯式卸載DLL。
使用LoadLibrary顯式鏈接,那么在函數的參數中可以指定DLL文件的完整路徑;如果不指定路徑,或者進行隱式鏈接,Windows將遵循下面的搜索順序來定位搜索DLL:
包含EXE文件的目錄
工程目錄
Windows系統目錄
Windows目錄
列在Path環境變量中的一系列目錄
2.2 靜態庫lib的使用
靜態lib中,一個lib文件實際上是任意個obj文件的集合,obj文件是cpp文件編譯生成的。靜態庫的.lib文件包含了鏈接庫的所有信息(函數代碼和接口信息)。所以我們在調用靜態庫.lib時,只需要包含頭文件目錄(../include. .h),以及附加庫目錄即可。因此,靜態鏈接庫的使用需要庫的開發者提供生成庫的.h頭文件和.lib文件
在VC中新建一個static library類型的工程TestLib,加入test.cpp文件和test.h文件(頭文件內包括函數聲明),然后編譯,就生成了TestLib.lib文件。
別的工程要使用這個lib方式:
(1)添加lib
方法1):直接用”項目右擊”->”添加”–>”現有項”–>選擇lib文件–>確定,通過這種方式將.lib加入工程
方法2):工程屬性-> 配置屬性->鏈接器->輸入->附加依賴項中添加要使用的Lib庫的名字;在工程屬性-> 配置屬性->鏈接器->輸入->附加庫目錄中輸入.lib文件所在路徑(相對或絕對路徑)
方法3):或者在源代碼中加入指令#pragma comment(lib, “TestLib.lib”),也可以指定完整路徑(絕對路徑或相對路徑)#pragma comment(lib, “..\Debug\TestLib.lib”)。可以通過宏#if defined(_DEBUG)來區分用release或debug版本的lib。另外這里如果不指定完整路徑,也要像方法2一樣添加附加庫目錄。
如果不在工程屬性中添加附加lib庫目錄,也可以將靜態里邊庫比如TestLib.lib拷貝到工程所在目錄,或者拷貝到執行文件生成的目錄,或者拷貝到系統Lib目錄中。
(2). 添加頭文件
加入相應的頭文件test.h。#include “test.h”
include file path可以為絕對路徑,也可以為相對於工程所在目錄的相對路徑,如果頭文件比較多,可以在project>settings>c/c++>preprocessor的Additional include directories中填入你的頭文件所在目錄,編譯時會自動在此目錄查找頭文件。
原文:windows中靜態庫lib和動態dll的區別及使用方法
