1. 程式人生 > >VC 執行時庫 /MD、/MDd 和 /MT、/MTd

VC 執行時庫 /MD、/MDd 和 /MT、/MTd

有段時間在寫cuda程式是出現過

error LNK2005: _exit 已經在 MSVCRTD.lib(MSVCR71D.dll) 中定義 等類似錯誤

原因應該是在vs2010 工程屬性中 c/c++的程式碼生成(code generation)中的設定與cuda c/c++ Host Runtime library不一樣導致的。 後來在寫opencv程式中的 findcontour()函式時,又是碰到 多執行緒除錯 (/MTD) 和 多執行緒除錯dll(/MDd)等問題,所以特此查了些內容。

1、 http://qimo601.iteye.com/blog/1550348

這裡總結下他們的區別,後面的那個'd'是代表DEBUG版本,沒有'd'的就是RELEASE版本了。

首先說/MT

/MT是 "multithread, static version ” 意思是多執行緒靜態的版本,定義了它後,編譯器把LIBCMT.lib 安置到OBJ檔案中,讓連結器使用LIBCMT.lib 處理外部符號。

/MD是 "multithread- and DLL-specific version” ,意思是多執行緒DLL版本,定義了它後,編譯器把MSVCRT.lib 安置到OBJ檔案中,它連線到DLL的方式是靜態連結,實際上工作的庫是MSVCR80.DLL。

即:

靜態執行時庫:LIBCMT.lib
動態執行時庫:MSVCRT.lib + MSVCR80.DLL

所以,當你用CMAKE生成工程檔案時,若CMAKE是用/MT生成的(檢視工程原始目錄的CMakeLists.txt),則它所呼叫的執行時庫為:LIBCMT.lib,若生成的工程的執行時庫(Runtime Library)你選擇/MD,則此工程在編譯後連結的時候,將會呼叫動態執行時庫:MSVCRT.lib + MSVCR80.DLL,明顯,兩次對同一個某執行時庫裡的函式呼叫的庫不同,則會出現重定義的錯誤。若此工程生成的是庫檔案,則其他工程呼叫此庫時也必須是/MT。

===============================================

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在非必要時最好也不要採用了。

2、 http://www.cnblogs.com/eddyshn/archive/2009/11/23/1608823.html

C編譯選項 多執行緒(/MT)
多執行緒除錯(/MTd)
多執行緒 DLL (/MD)
多執行緒除錯 DLL (/MDd)
C 執行時庫                        庫檔案
Single thread(static link) ML            libc.lib
Debug single thread(static link) MLd        libcd.lib
MultiThread(static link) MT            libcmt.lib
Debug multiThread(static link) MTd            libcmtd.lib
MultiThread(dynamic link) MD            msvert.lib
Debug multiThread(dynamic link) MDd        msvertd.lib 
3. 各種 C 執行時庫的區別
( 1 )靜態連結的單執行緒庫
靜態連結的單執行緒庫只能用於單執行緒的應用程式, C 執行時庫的目的碼最終被編譯在應用程式的二進位制檔案中。通過 /ML 編譯選項可以設定 Visual C++ 使用靜態連結的單線
程庫。
( 2 )靜態連結的多執行緒庫
靜態連結的多執行緒庫的目的碼也最終被編譯在應用程式的二進位制檔案中,但是它可以在多執行緒程式中使用。通過 /MT 編譯選項可以設定 Visual C++ 使用靜態連結的多執行緒庫。
( 3 )動態連結的執行時庫
動態連結的執行時庫將所有的 C 庫函式儲存在一個單獨的動態連結庫 MSVCRTxx.DLL 中, MSVCRTxx.DLL 處理了多執行緒問題。使用 /MD 編譯選項可以設定 Visual C++ 使用動態
連結的執行時庫。
/MDd 、 /MLd 或 /MTd 選項使用 Debug runtime library( 除錯版本的執行時刻函式庫 ) ,與 /MD 、 /ML 或 /MT 分別對應。 Debug 版本的 Runtime Library 包含了除錯資訊
,並採用了一些保護機制以幫助發現錯誤,加強了對錯誤的檢測,因此在執行效能方面比不上 Release 版本。 
下面是msdn關於Visual C++ 編譯器選項的說明:
這些選項選擇單執行緒或多執行緒執行時例程,指示多執行緒模組是否為 DLL,並選擇執行時庫的釋出版本或除錯版本。
選項     說明
/MD     定義 _MT 和 _DLL 以便同時從標準 .h 檔案中選擇執行時例程的多執行緒特定版本和 DLL 特定版本。此選項還使編譯器將庫名 MSVCRT.lib 放入 .obj 檔案中。
用此選項編譯的應用程式靜態連結到 MSVCRT.lib。該庫提供允許連結器解析外部引用的程式碼層。實際工作程式碼包含在 MSVCR71.DLL 中,該庫必須在執行時對於與 MSVCRT.lib 鏈
接的應用程式可用。
當在定義了 _STATIC_CPPLIB (/D_STATIC_CPPLIB) 的情況下使用 /MD 時,它將導致應用程式通過靜態多執行緒標準 C++ 庫 (libcpmt.lib) 而非動態版本 (msvcprt.lib) 進行連結
,同時仍通過 msvcrt.lib 動態連結到主 CRT。
/MDd     定義 _DEBUG、_MT 和 _DLL,以便從標準 .h 檔案中選擇執行時例程的除錯多執行緒特定版本和 DLL 特定版本。它還使編譯器將庫名 MSVCRTD.lib 放入 .obj 檔案中。
/ML     使編譯器將庫名 LIBC.lib 放入 .obj 檔案中,以便連結器使用 LIBC.lib 解析外部符號。這是編譯器的預設操作。LIBC.lib 不提供多執行緒支援。
/MLd     定義 _DEBUG 並使編譯器將庫名 LIBCD.lib 放入 .obj 檔案中,以便連結器使用 LIBCD.lib 解析外部符號。LIBCD.lib 不提供多執行緒支援。
/MT     定義 _MT,以便從標準頭 (.h) 檔案中選擇執行時例程的多執行緒特定版本。此選項還使編譯器將庫名 LIBCMT.lib 放入 .obj 檔案中,以便連結器使用 LIBCMT.lib 解析
外部符號。建立多執行緒程式需要 /MT     或 /MD(或它們的除錯等效選項 /MTd 或 /MDd)。
/MTd     定義 _DEBUG 和 _MT。定義 _MT 會導致從標準 .h 檔案中選擇執行時例程的多執行緒特定版本。此選項還使編譯器將庫名 LIBCMTD.lib 放入 .obj 檔案中,以便連結器使
用 LIBCMTD.lib 解析外部符號。創    建多執行緒程式需要 /MTd 或 /MDd(或它們的非除錯等效選項 /MT 或 MD)。
/LD     建立 DLL。
將 /DLL 選項傳遞到連結器。連結器查詢 DllMain 函式,但並不需要該函式。如果沒有編寫 DllMain 函式,連結器將插入返回 TRUE 的 DllMain 函式。
連結 DLL 啟動程式碼。
如果命令列上未指定匯出 (.exp) 檔案,則建立匯入庫 (.lib);將匯入庫連結到呼叫您的 DLL 的應用程式。
將 /Fe 解釋為命名 DLL 而不是 .exe 檔案;預設程式名成為基名稱.dll 而不是基名稱.exe。
如果還未顯式指定 /M 選項之一,則將預設執行時庫支援更改為 /MT。
/LDd     建立除錯 DLL。定義 _DEBUG。
    警告   不要混合使用執行時庫的靜態版本和動態版本。在一個程序中有多個執行時庫副本會導致問題,因為副本中的靜態資料不與其他副本共享。連結器禁止在 .exe 檔案內
部既使用靜態版本又使用動態版本連結,但您仍可以使用執行時庫的兩個(或更多)副本。例如,當與用動態 (DLL) 版本的執行時庫連結的 .exe 檔案一起使用時,用靜態(非 
DLL)版本的執行時庫連結的動態連結庫可能導致問題。(還應該避免在一個程序中混合使用這些庫的除錯版本和非除錯版本)。

3、 http://hi.baidu.com/musvision/item/80343d94ef7af3ecb725319a

IBCMTD.lib(crt0dat.obj) : error LNK2005: _exit 已經在 MSVCRTD.lib(MSVCR71D.dll) 中定義 等類似錯誤 
原因: 
Run-Time Library 
?Run-Time Library是編譯器提供的標準庫,提供一些基本的庫函式和系統呼叫。 
我們一般使用的Run-Time Library是C Run-Time Libraries。當然也有Standard C++ libraries。 
C Run-Time Libraries實現ANSI C的標準庫。VC安裝目錄的CRT目錄有C Run-Time庫的大部分原始碼。 C Run-Time Libraries有靜態庫版本,也有動態連結庫版本;有單執行緒版本,也有多執行緒版本;還有除錯和非除錯版本。
?動態連結庫版本: 
/MD Multithreaded DLL 使用匯入庫MSVCRT.LIB
/MDd Debug Multithreaded DLL 使用匯入庫MSVCRTD.LIB 
?靜態庫版本: 
/ML Single-Threaded 使用靜態庫LIBC.LIB
/MLd Debug Single-Threaded 使用靜態庫LIBCD.LIB
/MT Multithreaded 使用靜態庫LIBCMT.LIB
/MTd Debug Multithreaded 使用靜態庫LIBCMTD.LIB 
若要使用此執行時庫  請忽略這些庫  
單執行緒 (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 

解決方法: 
屬性,連結器,輸入,忽略指定庫 libc.lib、libcmt.lib、msvcrt.lib、libcd.lib、libcmtd.lib (使用一個,忽略其他的。還可以嘗試其他編譯選象)