爲何Windows下的動態庫總伴隨一個靜態庫?

今天同學來問了一個問題:Visual Studio中生成的動態庫總是伴隨着一個靜態庫文件,我把這兩個文件同樣進行重命名之後還能不能使用?

我對VS下的動態庫的生成並不是很熟悉,表示無法回答這個問題。但這個問題本身卻也讓我產生了疑問:動態庫真的需要總是伴隨着一個靜態庫?根據我在Linux下的經驗,這兩種形式的代碼庫是沒有什麼依賴關係的。 那在Windows下到底是怎麼回事?帶着這些疑問,我去搜索了一下。下面將得到的結論和一些相關知識進行總結。

靜態鏈接庫(.lib文件)其實是代碼的簡單集合,在Linux下擴展名爲.a,表示archive(歸檔)之意。它只是將編譯後的目標代碼(.o文件)進行簡單的歸檔,沒什麼特殊之處。我曾試過將Windows下的foo.lib文件直接命名爲foo.a,直接在Linux下使用 (當然,前提是他們含有的目標代碼必須一樣,即編譯時目標平臺是一致的)。這些庫在鏈接時被鏈接進可執行文件,如同.o文件被鏈接一樣。靜態庫的作用無非是將多個.o集成爲一個,便於管理和分享而已。

動態鏈接庫(.dll文件)則相對複雜一些。動態庫中的代碼是在運行時根據需要加載的。由於這裏面的代碼在加載進內存後可以被多個程序共享,因此又稱爲共享庫,在Linux下的擴展名爲.so,表示shared objects(共享的目標代碼)之意。

Windows下用VS創建DLL項目生成.dll文件時,一般會伴隨生成一個.lib文件;使用這個.dll文件時,需要將伴隨的.lib加進鏈接選項。事實上,這裏的.lib文件中只包含簡單的導出定義,實際的代碼還是在.dll文件中。這裏的.lib文件並非是上面提到的 靜態庫,而是動態鏈接庫的導入庫(Import Libary)。雖然共用擴展名,但它們的內容是完全不一樣的。導入庫只在鏈接的時候需要,程序運行的時候只需要.dll文件即可。此外,DLL項目中必須至少導出一個函數、變量或者類纔會有.lib生成, 沒有導出的話就不生成.lib文件。由於一般情況下DLL項目都是爲了導出符號給別的項目用,所以纔給人一種動態庫總伴隨着一個“靜態庫”文件的假象。

回到同學的問題。伴隨的那個.lib文件裏有相應的.dll文件的名字和一個指明.dll文件中函數入口的順序表。如果把.dll文件的名稱改了,.lib文件中相應的名字還是原來的文件名,應該就會找不到相應的.dll文件了。 但其實.dll文件在沒有.lib文件的情況下也是可以使用的:通過WIN32 API函數LoadLibrary、GetProcAddress等函數來調用.dll中的函數即可。但這樣比起有.lib文件時調用.dll中的函數稍微麻煩些。另外,Windows下也可以由.dll文件得到相應的.lib文件。 參見http://www.oschina.net/question/234345_48496

那爲什麼在Linux下用GCC生成和使用.so文件時不需要類似.lib導入庫這樣的東西呢?直接原因是Windows下的鏈接器只能處理.lib這樣的非可執行文件,不能處理.dll這樣的可執行文件,所以用一個導入庫(.lib)來輔助鏈接; 而在Linux下,.so文件是elf格式的,這種格式既可執行又能鏈接,所以GCC就沒必要使用額外的文件來輔助鏈接共享庫了。網上有人對Windows下導入庫的概念給出了更深層一點的解釋: DLL中導出的符號名未必是應用程序使用它時導入的符號名;爲了方便得到對語言中立的組件,微軟特意採用了現在的方案:在DLL裏導出一套符號,然後通過DEF文件或”Import Library”來使用另一套符號進行導入,這樣就相當於多了一層轉換,可兼顧同語言和跨語言的應用。 這也是有道理的。

轉:http://blog.shengbin.me/posts/windows-dll-with-lib/

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