2014-06-17 90 views
0

我有一個使用3-4個外部庫的C文件。它使用cl.exelink.exe(MSVC)構建。使用/ c和/ MD選項編譯C文件,然後鏈接.lib文件

構建腳本顯示生成exe文件的過程有兩個滑臺

  • 使用與cl.exe的「/ C」選項,以獲得.o文件。其他一些標誌也給出了這個,但我關心的是/MD。 MSDN說:

導致使用運行時庫的多線程特異性和DLL版本的應用程序。定義_MT和_DLL並使編譯器將庫名稱MSVCRT.lib放入.obj文件中。

什麼用的給/MDcl當我們只編譯,而不是鏈接?

  • 在此之後,link.exe用於生成exe。幾個.lib文件被指定爲鏈接(如ole32.lib,advapi32.lib,user32.lib等和其他非MSVC特定的文件)。我的問題是,不是.lib文件用於靜態鏈接?如果是,那麼爲什麼最終的exe只有大約500 KB? .lib都不是導入庫。

    如果不是,那麼link默認使用靜態或動態鏈接? cl給出的/MD在這裏有什麼作用嗎?

回答

2

原始的C運行時庫從來沒有想過必須支持從多個模塊構建的程序。它包含全局變量,如errnostdout以及具有隱式全局狀態的函數,如strtok()malloc()。您可以將DLL與他們自己的CRT副本鏈接起來,但這對設計DLL接口的方式提出了相當苛刻的要求。你必須非常小心地對從不依賴於CRT狀態。獲得這個錯誤幾乎不可能診斷運行時錯誤行爲。

對此的解決方法是在您的過程中只有一個一個 CRT副本。這是/ MD完成的,你最終會依賴於存儲在DLL中的CRT版本。由所有模塊共享。像msvcr120.dll一樣,由VS2013使用。

編譯器需要知道這個,以便它可以正確使用該DLL版本。一個簡單的例子是errno,它是一個帶有/ MT的全局變量,但是被宏編輯爲帶有/ MD的函數調用,因此只有DLL中的一個全局用於跟蹤最後一個已知值。如果在編譯器的.h文件中使用/ MD,則將定義_DLL宏。

另外一個副作用是編譯器自動爲msvcrt.lib或libcmt.lib插入鏈接指令(相當於#pragma註釋)。旨在幫助您避免錯誤,並省略明確指定CRT庫鏈接指令的需求。如果出現錯誤,則很難診斷鏈接器錯誤消息。與您嘗試鏈接.obj或。時獲得的種類不同。lib文件與/ MT和/ MD不匹配。哪一個當然不能正常工作,你不能對兩者都有依賴性。

中的.libs都不是導入庫

你的名字,ole32.lib,advapi32.lib,USER32.LIB列出的那些,其實都是導入庫。它們是標準的操作系統DLL。在運行時,程序將加載相應的DLL,從調試器中可以很容易看到。對於VS,你會在輸出窗口中看到它。值得注意的是,這些DLL實際上使用了與您的程序不同的CRT,它們綁定到c:\ windows \ system32 \ msvcrt.dll。 winapi經過精心設計,永遠不會造成這個問題。

做鏈接使用靜態或動態鏈接默認

沒有默認值,它取決於你鏈接的.lib。區分靜態鏈接庫和導入庫。導入庫是在構建DLL時創建的。它是一個不包含代碼的小文件,只是DLL中導出函數的名稱,因此鏈接器知道將條目放入程序的導入表中。當程序啓動時,DLL依賴項被解析並且導入的函數被加載器綁定。