一、MD(d)、MT(d)編譯選項的區別1、編譯選項的位置
以VS2005為例,這樣子開啟:
1) 開啟項目的Property Pages對話方塊
2) 點擊左側C/C++節
3) 點擊Code Generation節
4) 右側第六行Runtime Library項目
2、各個設定選項代表的含義
|
編譯選項 |
包含 |
靜態連結的lib |
說明 |
|
/MD |
_MT、_DLL |
MSVCRT.lib |
多線程、Release、DLL版本的執行階段程式庫 |
|
/MDd |
_DEBUG、_MT、_DLL |
MSVCRTD.lib |
多線程、Debug、DLL版本的執行階段程式庫 |
|
/MT |
_MT |
LIBCMT.lib |
多線程、Release版本的執行階段程式庫 |
|
/MTd |
_DEBUG、_MT |
LIBCMTD.lib |
多線程、Debug版本的執行階段程式庫 |
簡單的說:
(1)/MD,表示執行階段程式庫由作業系統提供一個DLL,程式裡不整合。
(2)/MT,表示執行階段程式庫由程式整合。
二、/MD、/MT的選擇 1、為什麼選擇/MD,不選/MT?
(1)程式就不需要靜態連結執行階段程式庫,可以減小軟體的大小;
(2)所有的模組都採用/MD,使用的是同一個堆,不存在A堆申請,B堆釋放的問題。
2、為什麼選擇/MT,不選擇/MD?
(1)有些系統可能沒有程式所需要版本的執行階段程式庫,程式必須把執行階段程式庫靜態連結上。
(2)減少模組對外界的依賴。
3、多個模組,必須選擇相同的執行階段程式庫。三、選擇/MT需要解決的堆空間釋放問題
不同的模組各自有一份C執行階段程式庫代碼、或者根本沒有C執行階段程式庫,導致了各個模組會有各自的堆。如果在A堆中申請空間,到B堆中釋放就會有崩潰,在模組A申請的空間,必須在模組A中釋放。
附錄的DLL以及DLLUser代碼,以STL的string為例,通過修改編譯選項驗證了這個問題。string在賦值的時候需要釋放掉原來的記憶體空間,然後再申請新的記憶體空間儲存新的內容,如果跨模組了,釋放的時候就存在“A模組申請B模組釋放”的問題,導致程式崩潰。
(跨模組釋放記憶體導致崩潰的內容,在《windows核心編程》第五版Page511談DLL和進程的地址空間時有談到)
四、選擇/MD需要注意多個模組使用不同版本執行階段程式庫的問題
(2012-9-17補充)
多個dll被一個exe LoadLibrary載入,如果這些dll使用的執行階段程式庫是不同的,那麼可能出現載入失敗,原因可能是舊版本的執行階段程式庫已經在了,而某個dll它需要的是新版本的執行階段程式庫,舊版本不符合要求。
如果工程裡所有的模組都是自己寫的或者可以完全控制的,那麼這個問題不難解決,只需要在工程設定裡都設定/MD,然後在相同的環境下編譯一次就行。但是假如這個模組是外界提供的呢?
可能存在這種情況:A動態庫使用了B靜態庫,B靜態庫使用了C動態庫,B靜態庫是外界提供的,我們要使用它,但無法修改它,我們也無法接觸到C動態庫。如果C動態庫使用的執行階段程式庫版本跟編譯A動態庫的本地使用的不一致,那麼A動態庫裡的嵌入資訊就會記錄兩個不同版本的執行階段程式庫,它被載入的時候,可能會選擇版本新的。假設A動態庫被一個exe LoadLibrary載入,而這個exe本身的執行階段程式庫是舊的,這樣就會導致A動態庫載入失敗,即便把新的執行階段程式庫拷貝到目錄下也不行,因為exe這個進程已經載入了那箇舊的執行階段程式庫。這時候必須使用manifest檔案指定嵌入到A動態庫裡的執行階段程式庫為某個版本,忽略掉C動態庫使用的執行階段程式庫版本。
這個問題挺複雜的,我心思沒去驗證windows的PE檔案載入會對執行階段程式庫做什麼樣的優先選擇、執行階段程式庫在靜態庫裡的記錄…。只要記住,給外界使用的組件版本盡量避免使用/MD(這樣會導致膨脹嗎?據說,安裝包可以做位元組流式壓縮)。
附上另一個問題:靜態庫的依賴關係:exe-->libA-->libB,現在不想讓exe接觸到libB,於是把libA的librarian選項-->General選項-->Link Library Dependencies設定為Yes,這樣即可,libA會包含libB,exe只需要接觸libA。另外需要特別注意,libA對libB的依賴只需要且只能在Solution的Project Dependencies裡設定,如果在libA的代碼裡寫了”#pragma comment(lib, "libB.lib")”,會導致exe在link libA的時候提示找不到libA。如果exe還出現link錯誤,那一定是VS抽筋了:)(2013.5.30補充)
四、參考資料
1、微軟關於MT、MD等的詳細介紹
http://msdn.microsoft.com/en-us/library/2kzt1wy3(v=VS.71).aspx
2、不要出現A模組申請,B模組釋放的情況
http://www.cnblogs.com/minggoddess/archive/2010/12/15/1907179.html
3、執行階段程式庫有哪些版本
http://www.cppblog.com/MichaelLiu/articles/10607.html
4、CSDN上關於堆空間釋放的討論
http://topic.csdn.net/t/20010112/09/57983.html
http://topic.csdn.net/t/20031009/17/2338051.html
http://topic.csdn.net/u/20090502/00/bf1602e3-ddf5-49b0-af81-8a23383f9ddc.html
http://blog.csdn.net/blz_wowar/article/details/2176536
5、不同模組不同的堆
http://www.cnblogs.com/WengYB/archive/2011/08/18/2144727.html
6、因為執行階段程式庫版本問題導致載入失敗的分享
http://blog.csdn.net/dev_yarin/article/details/6768373
http://blog.163.com/henan_lujun/blog/static/19538333200611485511640/
7、《windows核心編程》
附錄:
:http://files.cnblogs.com/cswuyg/Test_MD_and_MT.rar