2010-01-08 109 views
14

我有一個C++可執行文件,我正在動態鏈接幾個庫(Boost,Xerces-c和自定義庫)。爲什麼C++鏈接器在構建期間需要庫文件,即使我是動態鏈接?

我明白爲什麼我會要求.lib/.a文件,如果我選擇靜態鏈接這些庫(relevant SO question here)。但是,爲什麼我需要在鏈接我的可執行文件時提供相應的.lib/.so庫文件,如果我是動態鏈接到這些外部庫?

+2

鏈接器需要知道哪個DLL包含需要解析的導出。 .lib文件提供了此信息。 – 2010-01-08 20:10:49

回答

8

編譯器不知道動態鏈接,它只是知道函數通過它的原型存在。鏈接器需要lib文件來解析符號。 DLL的lib包含附加信息,比如函數所在的DLL以及它們如何導出(通過名稱,序號等)。DLL的lib文件包含的信息比包含完整對象代碼的lib文件要少得多 - libcmmt我的系統上的.lib是19.2 MB,但msvcrt.lib是「僅」2.6 MB。

請注意,此編譯/鏈接模型在這一點上已有近40年的歷史,並且早於大多數平臺上的動態鏈接。如果它是今天設計的,動態鏈接將成爲頭等公民(例如,在.NET中,每個程序集都有豐富的元數據,準確描述了它的輸出內容,因此您不需要單獨的頭文件和庫。)

+3

所以,如果我正確理解這一點:作爲'隱式'動態鏈接(構建期間與.lib鏈接,在運行時使用DLL)的替代方案 - 我可以'顯式'鏈接在運行時通過使用(在Windows上)LoadLibrary()加載DLL和GetProcAddress()以返回指向我調用的方法的函數指針。這是更多的代碼編寫,但在編譯時我不需要.lib。 – 2010-01-11 14:52:17

+0

你的理解是正確的。 – Michael 2010-01-11 17:21:07

1

有一件事,鏈接器插入鏈接時存在的庫的版本,以便在程序庫版本更新時有一定程度的工作機會。系統上可以存在多個版本的共享庫。

1

鏈接器具有驗證您的所有未定義符號是否包括靜態內容或動態內容的工作。

默認情況下,它堅持所有符號都存在。

但是,這只是默認設置。請參閱-z和--allow-shlib-undefined以及朋友。

0

也許這個動態鏈接是通過導入庫完成的(函數在定義之前有__declspec(dllimport))。
如果這是編譯器希望聲明__imp_symbol函數的方式,並且此函數負責將調用轉發到動態加載的正確庫。
這些功能是在符號與__declspec(dllimport)關鍵字鏈接過程中生成的。關鍵字

2

Raymond Chen寫了一些關於這個特定於Windows的博客文章。從The classical model for linking開始,然後跟進Why do we have import libraries anyway?。總之,歷史已經將編譯器定義爲知道詳細類型信息的組件,而鏈接器只知道符號名稱。因此,鏈接程序最終創建沒有類型信息的.DLL,因此希望與它鏈接的程序需要某種類型的元數據來告訴它如何導出函數以及它們返回和返回哪些參數類型。

原因.DLL沒有您需要直接與它們鏈接的所有信息是歷史性的,而不是技術限制。

0

這是一個非常簡單的說明,可能有所幫助。靜態鏈接將運行程序所需的所有代碼放入可執行文件中,以便找到所有內容。動態鏈接意味着一些所需的代碼不會被放入可執行文件中,並會在運行時找到。我在哪裏找到它?函數x()在那裏?如何調用函數x()?這是圖書館在動態鏈接時告訴鏈接器的內容。

相關問題