ZZmsvcprt.lib(MSVCP90.dll) : error LNK2005:已經在libcpmtd.lib(xmutex.obj) 中定義 .的分析解決辦法 (轉)

好久沒有寫程式設計入門知識的相關文章了,這篇文章要來談談程式庫 (Library) 連結,以及關於 MSVC 與 CRT 之間的種種恩怨情仇。html

若是你使用的做業系統是 Linux、Mac 或其餘非 Windows 平臺,你能夠忽略這篇文章;若是你使用的做業系統是 Windows 平臺,但沒有用 Microsoft Visual Studio C++(如下簡稱爲 MSVC)軟體撰寫 C++ 程式的話,這篇文章對你的幫助可能頗有限;但若是你的做業系統是 Windows,並且你使用的程式整合開發環境是 MSVC 軟體撰寫 C++ 程式的話,這篇文章應該可以幫助你釐清一些重要的基礎觀念。ios

身爲程式設計者,在學習程式設計的過程當中,你是否曾經遇過某些看起來不知所云的錯誤訊息,殊不知該如何解決?例如當你快快樂樂地寫完程式,而且確認全部的程式碼都能成功經過編譯以後,接着執行「建置方案」(Build Solution) 的步驟,結果卻跑出一堆莫名其妙的錯誤:安全

LIBCMTD.lib(mlock.obj) : error LNK2005: __lock 已在 MSVCRTD.lib(MSVCR80D.dll) 中定義過了 LIBCMTD.lib(mlock.obj) : error LNK2005: __unlock 已在 MSVCRTD.lib(MSVCR80D.dll) 中定義過了 LIBCMTD.lib(crt0.obj) : error LNK2005: _mainCRTStartup 已在 MSVCRTD.lib(crtexe.obj) 中定義過了函數

…………工具

LINK : warning LNK4098: 預設的程式庫 ‘MSVCRTD’ 與其餘使用的程式庫衝突,請使用 /NODEFAULTLIB:library LINK : warning LNK4098: 預設的程式庫 ‘LIBCMTD’ 與其餘使用的程式庫衝突,請使用 /NODEFAULTLIB:library D:\Workspace\CrtLibTest\Debug\CrtLibTest.exe : fatal error LNK1169: 找到有一或多個已定義的符號學習

以通常的狀況來講,若是在你的程式專案中有使用某些由他人所撰寫的第三方程式庫或是開源專案的程式庫,比較容易會發生上述的錯誤情況。從上述這些看似離奇而使人摸不着頭緒的錯誤訊息中,咱們大概能夠猜想問題點應該在於 LIBCMTD.lib 與 MSVCRTD.lib 這兩個程式庫身上。但到底什麼是 LIBCMTD.lib 和 MSVCRTD.lib?在咱們的程式碼中有使用這些程式庫嗎?ui

 

答案是確定的。lua

熟悉 C 語言的程式設計者都知道,若是要使用 printf()、scanf() 或者 fopen() 等等 C 語言的基本 I/O 操做函式時,首先必須用 #include 語法將 stdio.h 這個標頭檔歸入咱們的程式碼中。藉由 stdio.h 中對這些 I/O 操做函式所作出的函式宣告 (function declaration),編譯器 (Compiler) 才得以確認 printf、scanf 以及 fopen 等等都是合法可用的函式。spa

而當咱們撰寫的程式碼通過編譯器產出 OBJ 形式的檔案以後,須要再經由連結器 (Linker) 的處理程序,將程式碼中所有有使用到的函式定義 (function definition) 連結建置起來,纔可以產生出最後的程式執行檔。問題來了,咱們知道 printf、scanf 以及 fopen 的函式宣告存在於 stdio.h 當中,可是這些傢伙的函式定義,也就是真正的實作程式碼,究竟存放在什麼地方呢?設計

在 C 語言的標準程式庫中。

由 C 語言所制訂的標準程式庫,稱之爲「執行階段程式庫」,也就是 C Run-Time Library,一般可簡稱爲 CRT。在 C 語言的標準程式庫中,包含了一組經常使用的基礎函式,例如 I/O 處理與字串操做程序等等,因此只要咱們使用 C 語言撰寫程式碼,就必定要將編譯完成後的程式碼 OBJ 檔,連結至 C 語言的執行階段程式庫,纔可以產生出合法的 C 語言程式執行檔。

而 CRT 並不是只有單一一種版本存在。事實上,除了能夠依「除錯」與「釋出」用途分紅兩個版本以外,二者又可分別衍生分出「靜態連結」與「動態連結」兩種形式:

靜態連結

  • LIBCMTD.lib(除錯版本)
  • LIBCMT.lib

動態連結

  • MSVCRTD.lib(除錯版本)
  • MSVCRT.lib

雖然這四個 CRT 版本的用途與使用方式各不相同,但卻有個共通的特色,就是它們都是知足執行緒安全需求,可在多執行緒程式碼中安全使用的程式庫版本。事實上,在過去 MSVC 6 的版本中,原本還有另外兩個 LIBCD.lib(除錯版本)與 LIBC.lib 程式庫,是專門給單執行緒程式使用的 CRT 版本,可是這兩個選項自 MSVC 2005 開始就從設定選項中被刪除掉了,因此如今大多數程式設計者使用的都是多執行緒的 CRT 版本。

在程式庫連結 (library linking) 的行爲中,靜態連結和動態連結的分別,在於使用靜態連結時,會直接將程式庫的函式定義嵌入執行檔之中,而使用動態連結時,程式庫的函式定義則存在於另外的獨立檔案,一般是 DLL 格式的檔案中,而後與程式執行檔一同發佈給使用者。所以在檔案的尺寸上,使用動態連結的執行檔檔案,一般會比使用靜態連結的執行檔檔案來得更小一些。

使用動態連結 CRT 版本的好處,是可以將常用到的標準程式庫們獨立出來,放在 Windows 的系統資料夾中,以減小咱們建置出來的執行檔檔案尺寸。但反過來講,使用動態連結 CRT 版本的缺點也在於這些與執行檔相依爲命的 DLL 檔案上。舉例來講,若是程式以 MSVC 2005 建置出 Debug 組態的執行檔,則此執行檔須要有 msvcr80d.dll 存在才能順利執行;若是是 Release 組態,則相依於 msvcr80.dll。可是若是你把相同的程式碼拿到 MSVC 2008 上建置,產生出來的執行檔則相依於 msvcr90d.dll 與 msvcr90.dll 兩個不一樣的 DLL 檔案。不一樣版本的 MSVC,都會有各自不一樣的相依 DLL 檔案。

在 MSVC 的程式專案中,如何指定程式碼要使用靜態連結或者動態連結的 CRT 版本?其實很容易,只要在專案屬性的「C/C++」頁面中,選擇「程式碼產生」(Code Generation) 子頁面,其中有個「執行階段程式庫」(Runtime Library) 的項目,也就是專案中用來設定 CRT 連結版本的地方。其中總共有四個選項,正好對應於上述靜態連結與動態連結的四個不一樣程式庫版本。

  • 多執行緒偵錯 (/MTd):對應 LIBCMTD.lib
  • 多執行緒 (/MT):對應 LIBCMT.lib
  • 多執行緒偵錯 DLL (/MDd):對應 MSVCRTD.lib
  • 多執行緒 DLL (/MD):對應 MSVCRT.lib

若是你沒有作任何設定就開始建置程式的話,MSVC 的預設選項則會使用動態連結的版本。

c-runtime-library

C Runtime Library

請注意,以上只是單純 C 語言的程式庫而沒有包含 C++ 語言在內。若是你的程式系統中,有包含 C++ 語言的程式碼的話,那又是另一回事了。可是在專案屬性的頁面中,爲何找不到相關的設定選項呢?由於 MSVC 悄悄地幫程式設計者代勞處理掉了。只要在程式碼中使用 #include 語法歸入任何一個 C++ 的標頭檔,例如 iostream 或 fstream,MSVC 就會在連結器的運做階段中,自動幫咱們連結 C++ 的執行階段程式庫。而 C++ 的執行階段程式庫,一樣可分爲四個版本:

靜態連結

  • LIBCPMTD.lib(除錯版本)
  • LIBCPMT.lib

動態連結

  • MSVCPRTD.lib(除錯版本):執行檔相依於 MSVCP90D.dll
  • MSVCPRT.lib:執行檔相依於 MSVCP90.dll

至於程式執行檔使用的是靜態連結或者動態連結的版本,就仰賴於 C 語言的版本設定選項了。舉個例子來講,若是你撰寫了一個 Debug 組態的 C++ 程式,而且保留專案原先預設的建置選項(動態連結),那麼最終建置出來的程式執行檔將會相依於 MSVCR90D.dll 以及 MSVCP90D.dll 兩個 DLL 檔案。若是將相同的程式以 Release 組態建置完成,則會相依於 MSVCR90.dll 以及 MSVCP90.dll 兩者。

standard-cpp-library

Standard C++ Library

剛學習程式設計的入門者,常常會在滿心歡喜地完成一件程式做品而且傳給其餘人使用時,卻發現不能在別人的電腦上啓動程式,其實就是陷入了使用者電腦缺乏 DLL 檔案而沒法執行程式的窘境。有三種方法能夠解決這個使人困擾的問題:

  1. 使用者的電腦,必須先安裝「Visual C++ 可轉發套件」(MSVC 2008 或 MSVC 2005 )。
  2. 將所需的 DLL 檔案,例如 MSVCR90D.dll 與 MSVCP90D.dll,直接附在程式的下載包當中。
  3. 以靜態連結方式建置程式執行檔。

當你沒法肯定本身的程式或別人的程式,是否相依於某些特定的 DLL 檔案時,有一個很是好用的免費工具程式 Dependency Walker,能夠開啓 EXE 格式的執行檔或者 DLL 格式的動態程式庫,而後詳細地條列出它們所相依的 DLL 檔案。

瞭解了幾種不一樣的 CRT 版本選項以後,回到最前面的錯誤訊息問題,相信各位如今應該可以很清楚地理解,原來會發生這些奇怪的錯誤情況,是由於程式同時連結了 LIBCMTD.lib 與 MSVCRTD.lib 因此形成函式定義版本衝突。也就是說,程式連結器已經在其中一個 CRT 的版本中找到所需的函式定義,但此時卻又跳出另一位 CRT,也給了一份相同函式的實做版本,因此連結器沒法判斷應該忽略誰而且選擇誰。

而這個情況的發生緣由,就是你的程式與程式所連結的外部程式庫,使用了不一樣的 CRT 版本之故。例如,當你的程式使用了 Lua,天然必須連結至 Lua 的程式庫 lua5.1.lib,但若是 lua5.1.lib 是以靜態連結版本的 CRT 建置而成,而你的程式倒是以預設選項,動態連結 CRT 來建置程式執行檔的話,如此一來就會產生上述這些錯誤訊息了。至此,問題的答案已昭然若揭,解決方法有二種:其一是將 Lua 從新以動態連結 CRT 的方式建置出一個新的程式庫,其二則是將本身的程式專案改爲以靜態連結 CRT 方式建置。

換個角度想,當你身爲一位程式庫的設計開發者,想要將本身寫的東西分享給其餘人,但又不想要徹底開放本身撰寫的程式源碼時,至少能夠同時提供如下四種版本的程式庫,以妥善知足使用者的各類不一樣需求:

  • Debug:動態連結除錯版本
  • Release:動態連結版本
  • Debug_Static:靜態連結除錯版本
  • Release_Static:靜態連結版本

然而,有時候世界並不會運做得如此理想。在某些特殊的情況下,當咱們使用他人所寫的第三方程式庫時,有時可能只拿獲得其中某個特定的版本,例如 Release_Static 版本時,就頗有可能會遇到程式庫衝突的錯誤情形。此時就須要視專案的實際需求而定,能夠在專案屬性中指定「忽略特定程式庫」(Ignore Specific Library) 這個選項,讓程式碼連結器忽略某些程式庫,以此化解動靜程式庫或新舊程式庫之間的恩怨衝突。

小測驗:你所撰寫的程式,必須連結某個以靜態多執行緒 (/MT) CRT 建置而成的程式庫。若是你的程式在 Debug 組態下以多執行緒偵錯 (/MTd) 選項建置,是否會產生衝突?若是你的程式在 Release 組態下以多執行緒 (/MT) 選項建置,是否會產生衝突?是的話,應該如何解決?

 

 

上面的方法仍是不行!會出現其餘問題的。

如下是我摸索出的最新的解決方法:

首先,全部的lib文件,使用/MTd或/MT編譯。Debug調試模式使用/MTd,Release模式使用/MT。

而後,在本身的程序中也使用/MTd或/MT編譯。這樣就不會出問題了。

三種編譯連接庫的方式:

(1)鏈接Windows庫。針對Win32 API編寫的應用程序,上面的方法可能帶來新問題,能夠忽略libcmt.lib庫,便可。若是還有其餘問題,再忽略相應的庫。

(2)MFC靜態連接。上面的方法就是針對這種連接方式的,因此沒問題。

(3)MFC動態連接。沒有試過,應該和(1)相似。

 

最後補充:若是還不行,直接加入/force:multiple編譯參數吧。此次之因此沒有使用它,也是爲了嚴謹起見。

 

另一個方式是:======================   個人作法是 把衝突的 都在忽略庫裏 加上

 

 

 

附其餘問題解決辦法:

完美解決#define _AFXDLL or do not use  

 

這個問題常常出如今嘗試使用Visual Studio 較高版本(2008,2010)編輯較低版本(Visual C++ 6.0)時使用「在靜態庫中使用MFC」的狀況。在·在網上查找方法,無非是「改爲在共享DLL中使用MFC」,或者將#include <afx.h>改爲<atlstr.h>等方法。筆者何嘗試過第二種方法,可是第一種卻是確實好用。第二種不推薦,由於若是使用了afx.h中的函數和變量,atlstr.h沒有怎麼辦?

 

解決方案:項目屬性(Alt+F7)——C/C++——代碼生成——

 

若是是Debug的「在靜態庫中使用MFC」,不要使用MDd,改用MTd,而後編譯便可經過。

 

若是是Debug的「在共享DLL中使用MFC」,注意不要使用MTd,改用MDd;

 

若是是Release版本「在靜態庫中使用MFC」,不要使用MD,使用MT;

 

若是是Release版本的「在共享DLL中使用MFC」,不要使用MT,使用MD。

 

 

from:http://www.cnblogs.com/minggoddess/archive/2010/12/29/1921077.html

相關文章
相關標籤/搜索