VC項目屬性→配置屬性→C/C++→代碼產生→執行階段程式庫 可以採用的方式有:多線程(/MT)、多線程調試(/MTd)、多線程DLL(/MD)、多線程調試DLL(/MDd)、單線程(/ML)、單線程調試(/MLd)。
| Reusable Library |
Switch |
Library |
Macro(s) Defined |
| Single Threaded |
/ML |
LIBC |
(none) |
| Static MultiThread |
/MT |
LIBCMT |
_MT |
| Dynamic Link (DLL) |
/MD |
MSVCRT |
_MT and _DLL |
| Debug Single Threaded |
/MLd |
LIBCD |
_DEBUG |
| Debug Static MultiThread |
/MTd |
LIBCMTD |
_DEBUG and _MT |
| Debug Dynamic Link (DLL) |
/MDd |
MSVCRTD |
_DEBUG, _MT, and _DLL |
其中以小寫“d”結尾的選項表示的DEBUG版本的,沒有“d”的為RELEASE版本。大型項目中必須要求所有組件和第三方庫的執行階段程式庫是統一的,否則將會出現LNK2005井噴。
單線程執行階段程式庫選項/ML和/MLd在VS2003以後就被廢了。
/MT和/MTd表示採用多線程CRT庫的靜態lib版本。該選項會在編譯時間將執行階段程式庫以靜態lib的形式完全嵌入。該選項產生的可執行檔運行時不需要執行階段程式庫dll的參加,會獲得輕微的效能提升,但最終產生的二進位代碼因鏈入龐大的執行階段程式庫實現而變得非常臃腫。當某項目以靜態連結庫的形式嵌入到多重專案,則可能造成執行階段程式庫的記憶體管理有多份,最終將導致致命的“Invalid Address specified to RtlValidateHeap”問題。另外託管C++和CLI中不再支援/MT和/MTd選項。
/MD和/MDd表示採用多線程CRT庫的動態dll版本,會使應用程式使用執行階段程式庫特定版本的多線程DLL。連結時將按照傳統VC連結dll的方式將執行階段程式庫MSVCRxx.DLL的匯入庫MSVCRT.lib連結,在運行時要求安裝了相應版本的VC執行階段程式庫可轉散發元件包(當然把這些執行階段程式庫dll放在應用程式目錄下也是可以的)。 因/MD和/MDd方式不會將執行階段程式庫連結到可執行檔內部,可有效減少可執行檔尺寸。當多項目以MD方式運作時,其內部會採用同一個堆,記憶體管理將被簡化,跨模組記憶體管理問題也能得到緩解。
結論:/MD和/MDd將是潮流所趨,/ML和/MLd方式請及時放棄,/MT和/MTd在非必要時最好也不要採用了。
以前經常遇到這個警告資訊,因為運行並沒有什麼問題,所以也沒深究。但是耿耿於懷那個“ 0 個錯誤,0 個警告”的成功提示,在網上搜了一下。原來問題出在預設庫的引用選擇上。
VS2008,項目——屬性——配置屬性——C/C++——代碼產生:他有/MT,/MTd,/Md,/MDd四個選項,你必須讓所有使用的庫都使用相同的配置,否則就會有相應的提示,甚至可能會出現無法解析的函數。有時我們使用的庫不是自己可以控制的,那麼就只能把工程屬性設定成河你使用的庫相同的選項。
錯誤 1 error LNK2005: _free 已經在 libcmtd.lib(dbgheap.obj) 中定義 MSVCRT.lib
錯誤 2 error LNK2005: _malloc 已經在 libcmtd.lib(dbgheap.obj) 中定義 MSVCRT.lib
.....
如果有一堆的重定義錯誤發生在同一個lib中,而且跟它衝突的也是同一個lib,那麼這個兩個lib的功能應該是一樣的,可以2選一,只要在“忽略特定的庫”內填入需要忽略的庫。
項目屬性-配置屬性-連結器-輸入-忽略特定的庫:libcmtd.lib
項目屬性-配置屬性-常規-MFC的使用:在共用 DLL 中使用 MFC
MSVCRT.lib 和libcmt.lib的衝突還是比較常見的。
從錯誤資訊可以看出是msvcrt.lib和libcmt.lib庫中重複定義了__isctype等符號。為什麼會出現這樣的問題呢?這就要從這兩個庫的作用說起了。
msvcrt.lib是VC中的Multithreaded DLL 版本的C執行階段程式庫,而libcmt.lib是Multithreaded的執行階段程式庫。在同一個項目中,所有的源檔案必須連結相同的C執行階段程式庫。如果某一文 件用了Multithreaded DLL版本,而其他檔案用了Single-Threaded或者Multithreaded版本的庫,也就是說用了不同的庫,就會導致這個警告的出現。
警示資訊的意思我們明白之後,就要找造成這個問題的原因了。在項目設定中我們可以看到當前項目使用的是Multithreaded非DLL版本的運 行時庫,這說明項目中還有其他檔案用到了不是這個版本的執行階段程式庫。很顯然,就是openssl的靜態庫。查看openssl中ms下的nt.mak,我們 可以發現靜態庫版本中openssl使用編譯開關/MD進行編譯的,也就是說openssl靜態庫是預設用的Multithreaded DLL 版本的C執行階段程式庫。
原因找到了。那麼解決方案,很明顯有兩個。總之就是將兩個項目的執行階段程式庫統一。
簡單的方式就是將項目的動態庫修改為使用Multithreaded DLL 版本的C執行階段程式庫即可。
某些情況下你的項目可能不能改變當前的執行階段程式庫,你可以將openssl的nt.mak中的/MD開關修改為/MT然後重新編譯openssl靜態庫就可以了。
預設庫“library”與其他庫的使用衝突;請使用 /NODEFAULTLIB:library LNK4098 的解決辦法
您試圖與不相容的庫連結。
注意
執行階段程式庫現在包含可防止混合不同類型的指令。如果試圖在同一個程式中使用不同類型的運行 時庫或使用調試和非調試版本的執行階段程式庫,則將收到此警告。例如,如 果編譯一個檔案以使用一種執行階段程式庫,而編譯另一個檔案以使用另一種執行階段程式庫(例如單線程執行階段程式庫對多線程執行階段程式庫),並試圖連結它們,則將得到此警告。應 將所有源檔案編譯為使用同一個執行階段程式庫。有關更多資訊,請參見使用執行階段程式庫(/MD、/MT 和 /LD)編譯器選項。
可以 使用連結器的 /VERBOSE:LIB 開關來確定連結器搜尋的庫。如果收到 LNK4098,並想建立使用如單線程、非調試執行階段程式庫的可執行檔,請使用 /VERBOSE:LIB 選項確定連結器搜尋的庫。連結器作為搜尋的庫輸出的應是 LIBC.lib,而非 LIBCMT.lib、MSVCRT.lib、LIBCD.lib、LIBCMTD.lib 和 MSVCRTD.lib。對每個要忽略的庫可以使用 /NODEFAULTLIB,以通知連結器忽略錯誤的執行階段程式庫。
下表顯示根據要使用的執行階段程式庫應忽略的庫。
若要使用第一行執行階段程式庫 請忽略第2行的這些庫
單線程 (libc.lib)
libcmt.lib、msvcrt.lib、libcd.lib、libcmtd.lib、msvcrtd.lib
多線程 (libcmt.lib)
libc.lib、msvcrt.lib、libcd.lib、libcmtd.lib、msvcrtd.lib
使用 DLL 的多線程 (msvcrt.lib)
libc.lib、libcmt.lib、libcd.lib、libcmtd.lib、msvcrtd.lib
調試單線程 (libcd.lib)
libc.lib、libcmt.lib、msvcrt.lib、libcmtd.lib、msvcrtd.lib
調試多線程 (libcmtd.lib)
libc.lib、libcmt.lib、msvcrt.lib、libcd.lib、msvcrtd.lib
使用 DLL 的調試多線程 (msvcrtd.lib)
libc.lib、libcmt.lib、msvcrt.lib、libcd.lib、libcmtd.lib
例如,如果收到此警告,並希望建立使用非調試、單線程版本的執行階段程式庫的可執行檔,可以將下列選項與連結器一起使用:
/NODEFAULTLIB:libcmt.lib /NODEFAULTLIB:msvcrt.lib /NODEFAULTLIB:libcd.lib /NODEFAULTLIB:libcmtd.lib /NODEFAULTLIB:msvcrtd.lib