.dll,.lib,.def 和 .exp檔案

yangzhao0001發表於2015-09-11

 簡要的介紹一下在微軟開發工具中(VC)靜態連結庫和動態連結庫生成過程中出現的.dll  .lib  .def 和 .exp檔案型別。windows平臺上可執行檔案可能是一個.exe檔案也可能四個.dll檔案。當然也有一些比較特別的exe或者dll檔案,不過他們有其他樣式的字尾名比如屏保程式(.scr),ActiveX DLL 用的.ocx 還有各種驅動使用的各種副檔名。這裡我們不討論.com 和一些指令碼檔案比如.bat .cmd等,雖然他們仍然是可執行檔案。

    庫就是包含著一坨資料和程式碼的東西,這個東西可以被連線程式或者其他可執行檔案使用。庫中這些可使用的物件(資料或者函式)使用一些標記標出來。比如在.obj目標檔案中一些簡單的符號。這裡討論到兩種型別的連結庫,靜態連結庫和動態連結庫。

     你可以認為靜態連結庫是一堆目標檔案(.obj)檔案的集合,我們只是把他們簡單的打包在了一半靜態連結庫中。靜態連結庫都有一個.lib的副檔名。靜態連結庫不是用來執行的但它可以被連結程式(link.exe)在生成可執行檔案的時候使用。在預設的情況下,靜態連結庫中所有的符號標記對於linker來說都是可見的,即可使用的。當然在編譯你的時候你需要對應好標頭檔案和靜態連結庫,一個靜態連結庫和.def 或者.exp檔案沒有任何的關係。

    這裡一個缺點就是,當我們使用靜態連結庫連結生成程式的時候,它裡面的一些物件比如函式程式碼都會拷貝到對應的程式當中去,這個工作原理和.obj檔案的使用時的工作原理是一樣的。對於一些在不同應用程式中可重複利用的程式碼來說這並不是意見好事:當我們連結的時候,每一個應用程式中都會有一個.obj中使用到的物件的拷貝。

    動態連結庫(DLL,在Unix世界中被稱作共享目標即.so檔案)可以幫我們節省記憶體空間。當我們連結到一個dll的時候,不會有程式碼拷貝到目標可執行檔案裡面,但是會有一個引用放在可執行檔案裡面。當可執行檔案被載入執行的時候系統會檢查它使用到的dll然後載入這些dll。使用dll我們可以很方便的升級我們的客戶端程式,而不用再次更新可執行檔案。

    但是在連結linking的時候我們還必須有一些資訊來知道怎樣連結到dll,比如標頭檔案中對應dll中的一些函式的簽名。連結程式需要更多的資訊,比如dll的檔名,那些符號可用等等,這些資訊存在於匯出庫檔案中。匯出庫的字尾名也是一個.lib。當linker生成.dll檔案的時候,他會自動的生成一個匯出庫.lib檔案。匯出庫被用來分發給那些在開發階段使用到這個dll的研發人員,更精確的說,是在他們使用link的時候。在使用的時候匯出庫的使用和靜態連結庫的使用基本沒啥區別。就是使用匯出庫的程式在執行的時

候需要對應匯出庫的dll。

     好吧!問題看似解決了,但是為什麼我們會看到到處都會出現一些.def檔案啊?

     def檔案(module definition file模組定義檔案)是用來建立dll和對應的匯出庫的。在一個.def檔案中,你可以指定dll將會匯出哪些符號給使用者使用。linker會根據def檔案的說明來生成dll和lib。一般的,dll的使用者不會對def檔案感興趣(我是指使用dll的開發者和使用最終產品的使用者)。注意他和靜態連結庫的不同點,預設的情況下,dll內部的符號是不可見的。我們有方法讓他們可見--在def檔案中使用exports語句。但是我們還有其他的方法,比如zaidll的原始碼中使用__declspec(dllexport)或者在linker的選項中

使用 /EXPORT 選項來匯出一個函式等等。事實上現在__declspec(dllexport)使用很多,而def檔案很少使用了。使用def檔案,你可以指示連結程式linker其他的一些資訊而不是匯出動作,比如堆疊的大小等等。但是這些選項經常在linker的命令列中標明瞭。事實上,def檔案在早期win16的dll程式設計中使用現在在win32中我們基本上把它給拋棄了,以後也是如此。

     稍等,在某些地方我們還看到一些.exp檔案?exp檔案就是匯出檔案(export file)。在前面的討論中,我們討論了使用linker去建立dll(中間還有它的匯出庫)現在,我們假設我們生成兩個dll(or just executables)。但是他們都需要呼叫一些對方中函式,問題出現了。當我們生成a.dll的時候我們需要b.lib;但是b.lib在對應的b.dll生成之前沒有生成,而b.dll的生成又需要a.lib。正因如此,微軟的解決辦法是使用exp檔案,或者叫匯出檔案。在生成兩個dll之前,你使用lib.exe(library mangager tool庫管理工具)來建立一個.lib和.exp,即,DLL A 的a.lib 和a.exp,現在linker使用a.lib和DLL B 自己的東西去生成b.dll和b.lib。當你回來連結DLL A的時候你就有了b.lib。這裡linker需要知道a.dll中需要匯出處啥。這些資訊都被快取到了a.exp檔案中。linker不需要def檔案或者/EXPORT選項,它僅僅是載入a.exp中的資訊。a.exp就像a.dll的兩個生成過程(lib.exe and linker)的聯絡者一樣。相似的,linker不會再次生成a.lib。總的來說,這種迴圈呼叫的情況不會和在我們的程式中出現,因此,希望你不會再你的程式中用到exp檔案。

http://blog.csdn.net/zhuxiaoyang2000/article/details/6387247

http://blog.csdn.net/zhuxiaoyang2000/article/category/820015

相關文章