[转]关于形如--error LNK2005: xxx 已经在 msvcrtd.lib ( MSVCR90D.dll ) 中定义--的问题分析解决...
關(guān)于形如--error LNK2005: xxx 已經(jīng)在 msvcrtd.lib ( MSVCR90D.dll ) 中定義--的問(wèn)題分析解決
轉(zhuǎn)自:http://hi.baidu.com/qinfengxiaoyue/item/ff262ccfb53b4c2ba0b50a89
引自:http://blog.csdn.net/sptoor/archive/2011/02/23/6203376.aspx
對(duì)全文有改動(dòng)。
提示:閱讀前需要對(duì)靜態(tài)庫(kù)(.lib)、動(dòng)態(tài)庫(kù)(.dll)、導(dǎo)入庫(kù)(這個(gè)還是.lib)之間的區(qū)別聯(lián)系有了解。建議先讀讀宋寶華先生的《VC++動(dòng)態(tài)鏈接庫(kù)(DLL)編程深入淺出 》
關(guān)鍵詞:程序庫(kù)、CRT、LIBCMTD.lib、MSVCRTD.lib、鏈接庫(kù)的沖突問(wèn)題、MSVC鏈接處理
?
1.問(wèn)題引出
?
很久沒(méi)有寫(xiě)程序設(shè)計(jì)入門(mén)知識(shí)的相關(guān)文章了,這篇文章要來(lái)談?wù)劤绦驇?kù) (Library) 鏈接,以及關(guān)于 MSVC 與 CRT 之間的種種
恩怨情仇。
如果你使用的操作系統(tǒng)是 Linux、Mac 或其他非 Windows 平臺(tái),你可以忽略這篇文章;如果你使用的操作系統(tǒng)是
Windows 平臺(tái),但沒(méi)有用 Microsoft Visual Studio C++(以下簡(jiǎn)稱(chēng)為 MSVC)軟件撰寫(xiě) C++ 程序的話,這篇文章對(duì)你的
幫助可能很有限;但如果你的操作系統(tǒng)是 Windows,而且你使用的程序整合開(kāi)發(fā)環(huán)境是 MSVC 軟件撰寫(xiě) C++ 程序的話,這
篇文章應(yīng)該能夠幫助你釐清一些重要的基礎(chǔ)觀念。
身為程序設(shè)計(jì)者,在學(xué)習(xí)程序設(shè)計(jì)的過(guò)程中,你是否曾經(jīng)遇過(guò)某些看起來(lái)不知所云的錯(cuò)誤信息,卻不知該如何解決?例如當(dāng)你
快快樂(lè)樂(lè)地寫(xiě)完程序,并且確認(rèn)所有的程序代碼都能成功通過(guò)編譯之后,接著執(zhí)行「生成解決方案」(Build Solution) 的步
驟,結(jié)果卻跑出一堆莫名其妙的錯(cuò)誤:
1>libcmtd.lib(errmode.obj) : error LNK2005: ___set_app_type 已經(jīng)在msvcrtd.lib(MSVCR90D.dll) 中定義
1>libcmtd.lib(dbgrptw.obj) : error LNK2005: __CrtDbgReport已經(jīng)在msvcrtd.lib(MSVCR90D.dll) 中定義
1>msvcrtd.lib(MSVCR90D.dll) : error LNK2005: __setmbcp 已經(jīng)在libcmtd.lib(mbctype.obj) 中定義
1>LINK:warning LNK4098:默認(rèn)庫(kù)“msvcrtd.lib”與其他庫(kù)的使用沖突;請(qǐng)使用/NODEFAULTLIB:library
1>msvcrtd.lib(cinitexe.obj) : warning LNK4098: 默認(rèn)庫(kù)“l(fā)ibcmtd.lib”與其他庫(kù)的使用沖突;請(qǐng)使
用/NODEFAULTLIB:library
.....................
以一般的情況來(lái)說(shuō),如果在你的程序項(xiàng)目中有使用某些由他人所撰寫(xiě)的第三方程序庫(kù)或是開(kāi)源項(xiàng)目的程序庫(kù),比較容易會(huì)發(fā)生
上述的錯(cuò)誤狀況。從上述這些看似離奇而令人摸不著頭線程的錯(cuò)誤信息中,我們大概可以猜測(cè)問(wèn)題點(diǎn)應(yīng)該在于 LIBCMTD.lib
與 MSVCRTD.lib 這兩個(gè)程序庫(kù)身上。但到底什么是 LIBCMTD.lib 和 MSVCRTD.lib?在我們的程序代碼中有使用這些程序
庫(kù)嗎?
答是肯定的。
?
2.C Runtime Library(C運(yùn)行時(shí)庫(kù))
熟悉 C 語(yǔ)言的程序設(shè)計(jì)者都知道,如果要使用 printf()、scanf() 或者 fopen() 等等 C 語(yǔ)言的基本 I/O 操作函數(shù)時(shí),首先
必須用 #include 語(yǔ)法將 stdio.h 這個(gè)標(biāo)頭文件納入我們的程序代碼中。藉由 stdio.h 中對(duì)這些 I/O 操作函數(shù)所做出的函數(shù)
聲明 (function declaration),編譯器 (Compiler) 才得以確認(rèn) printf、scanf 以及 fopen 等等都是合法可用的函數(shù)。
而當(dāng)我們撰寫(xiě)的程序代碼經(jīng)過(guò)編譯器產(chǎn)出 OBJ 形式的文件之后,需要再經(jīng)由鏈接器 (Linker) 的處理程序,將程序代碼中全部
有使用到的函數(shù)定義 (function definition) 鏈接生成起來(lái),才能夠產(chǎn)生出最后的程序執(zhí)行文件。問(wèn)題來(lái)了,我們知道 printf、
scanf 以及 fopen 的函數(shù)聲明存在于 stdio.h 當(dāng)中,但是這些傢伙的函數(shù)定義,也就是真正的定義程序代碼,究竟存放在什么
地方呢?
在 C 語(yǔ)言的標(biāo)準(zhǔn)程序庫(kù)中。
由 C 語(yǔ)言所制訂的標(biāo)準(zhǔn)程序庫(kù),稱(chēng)之為「執(zhí)行階段程序庫(kù)」,也就是 C Run-Time Library,通常可簡(jiǎn)稱(chēng)為 CRT。在 C 語(yǔ)
言的標(biāo)準(zhǔn)程序庫(kù)中,包含了一組常用的基礎(chǔ)函數(shù),例如 I/O 處理與字串操作程序等等,所以只要我們使用 C 語(yǔ)言撰寫(xiě)程序代
碼,就一定要將編譯完成后的程序代碼 OBJ 文件,鏈接至 C 語(yǔ)言的執(zhí)行階段程序庫(kù),才能夠產(chǎn)生出合法的 C 語(yǔ)言程序執(zhí)行文
件。
而 CRT 并非只有單一一種版本存在。事實(shí)上,除了可以依「Debug」與「Release」用途分成兩個(gè)版本之外,兩者又可分別
衍生分出「靜態(tài)鏈接」與「動(dòng)態(tài)鏈接」兩種形式:
靜態(tài)鏈接:
LIBCMTD.lib(Debug版本)
LIBCMT.lib
動(dòng)態(tài)鏈接:
MSVCRTD.lib(Debug版本)
MSVCRT.lib
雖然這四個(gè) CRT 版本的用途與使用方式各不相同,但卻有個(gè)共通的特點(diǎn),就是它們都是滿(mǎn)足執(zhí)行線程安全需求,可在多執(zhí)行線
程程序代碼中安全使用的程序庫(kù)版本。事實(shí)上,在過(guò)去 MSVC 6 的版本中,本來(lái)還有另外兩個(gè) LIBCD.lib(Debug版本)與
LIBC.lib 程序庫(kù),是專(zhuān)門(mén)給單執(zhí)行線程程序使用的 CRT 版本,但是這兩個(gè)選項(xiàng)自 MSVC 2005 開(kāi)始就從設(shè)定選項(xiàng)中被刪除掉
了,所以現(xiàn)在大多數(shù)程序設(shè)計(jì)者使用的都是多執(zhí)行線程的 CRT 版本。
在程序庫(kù)鏈接 (library linking) 的行為中,靜態(tài)鏈接和動(dòng)態(tài)鏈接的分別,在于使用靜態(tài)鏈接時(shí),會(huì)直接將程序庫(kù)的函數(shù)定義嵌
入執(zhí)行文件之中,而使用動(dòng)態(tài)鏈接時(shí),程序庫(kù)的函數(shù)定義則存在于另外的獨(dú)立文件,通常是 DLL 格式的文件中,然后與程序執(zhí)
行文件一同發(fā)布給使用者。因此在文件的尺寸上,使用動(dòng)態(tài)鏈接的執(zhí)行文件文件,通常會(huì)比使用靜態(tài)鏈接的執(zhí)行文件文件更小
一些。
使用動(dòng)態(tài)鏈接 CRT 版本的好處,是能夠?qū)⒔?jīng)常使用到的標(biāo)準(zhǔn)程序庫(kù)們獨(dú)立出來(lái),放在 Windows 的系統(tǒng)文件夾中,以減少我
們生成出來(lái)的執(zhí)行文件文件尺寸。但反過(guò)來(lái)說(shuō),使用動(dòng)態(tài)鏈接 CRT 版本的缺點(diǎn)也在于這些與執(zhí)行文件相依為命的 DLL 文件
上。舉例來(lái)說(shuō),如果程序以 MSVC 2005 生成出 Debug 態(tài)的執(zhí)行文件,則此執(zhí)行文件需要有 msvcr80d.dll 存在才能順利執(zhí)
行;如果是 Release 態(tài),則相依于 msvcr80.dll。但是如果你把相同的程序代碼拿到 MSVC 2008 上生成,產(chǎn)生出來(lái)的執(zhí)行
文件則相依于 msvcr90d.dll 與 msvcr90.dll 兩個(gè)不同的 DLL 文件。不同版本的 MSVC,都會(huì)有各自不同的相依 DLL 文
件。
在 MSVC 的程序項(xiàng)目中,如何指定程序代碼要使用靜態(tài)鏈接或者動(dòng)態(tài)鏈接的 CRT 版本?其實(shí)很容易,只要在項(xiàng)目屬性的
「C/C++」頁(yè)面中,選擇「程序代碼產(chǎn)生」(Code Generation) 子頁(yè)面,其中有個(gè)「執(zhí)行階段程序庫(kù)」(Runtime Library)
的項(xiàng)目,也就是項(xiàng)目中用來(lái)設(shè)定 CRT 鏈接版本的地方。其中總共有四個(gè)選項(xiàng),正好對(duì)應(yīng)于上述靜態(tài)鏈接與動(dòng)態(tài)鏈接的四個(gè)不同
程序庫(kù)版本。
多執(zhí)行線程調(diào)試 (/MTd):對(duì)應(yīng) LIBCMTD.lib
多執(zhí)行線程 (/MT):對(duì)應(yīng) LIBCMT.lib
多執(zhí)行線程調(diào)試 DLL (/MDd):對(duì)應(yīng) MSVCRTD.lib
多執(zhí)行線程 DLL (/MD):對(duì)應(yīng) MSVCRT.lib
如果你沒(méi)有做任何設(shè)定就開(kāi)始生成程序的話,MSVC 的預(yù)設(shè)選項(xiàng)則會(huì)使用動(dòng)態(tài)鏈接的版本。
?
3.Standard C++ Library(標(biāo)準(zhǔn)C++庫(kù))
請(qǐng)注意,以上只是單純 C 語(yǔ)言的程序庫(kù)而沒(méi)有包含 C++ 語(yǔ)言在內(nèi)。如果你的程序系統(tǒng)中,有包含 C++ 語(yǔ)言的程序代碼的
話,那又是另外一回事了。但是在項(xiàng)目屬性的頁(yè)面中,為什么找不到相關(guān)的設(shè)定選項(xiàng)呢?因?yàn)?MSVC 悄悄地幫程序設(shè)計(jì)者代勞
處理掉了。只要在程序代碼中使用 #include 語(yǔ)法納入任何一個(gè) C++ 的標(biāo)頭文件,例如 iostream 或 fstream,MSVC 就
會(huì)在鏈接器的運(yùn)作階段中,自動(dòng)幫我們鏈接 C++ 的執(zhí)行階段程序庫(kù)。而 C++ 的執(zhí)行階段程序庫(kù),同樣可分為四個(gè)版本:
靜態(tài)鏈接:
LIBCPMTD.lib(Debug版本)
LIBCPMT.lib
動(dòng)態(tài)鏈接:
MSVCPRTD.lib(Debug版本):執(zhí)行文件相依于 MSVCP90D.dll
MSVCPRT.lib:執(zhí)行文件相依于 MSVCP90.dll
?
至于程序執(zhí)行文件使用的是靜態(tài)鏈接或者動(dòng)態(tài)鏈接的版本,就仰賴(lài)于 C 語(yǔ)言的版本設(shè)定選項(xiàng)了。舉個(gè)例子來(lái)說(shuō),如果你撰寫(xiě)了
一個(gè) Debug 組態(tài)的 C++ 程序,并且保留項(xiàng)目原先預(yù)設(shè)的生成選項(xiàng)(動(dòng)態(tài)鏈接),那么最終生成出來(lái)的程序執(zhí)行文件將會(huì)相
依于 MSVCR90D.dll 以及 MSVCP90D.dll 兩個(gè) DLL 文件。如果將相同的程序以 Release 組態(tài)生成完成,則會(huì)相依于
MSVCR90.dll 以及 MSVCP90.dll 二者。
?
4.問(wèn)題分析及解決
剛學(xué)習(xí)程序設(shè)計(jì)的入門(mén)者,經(jīng)常會(huì)在滿(mǎn)心歡喜地完成一件程序作品并且傳給其他人使用時(shí),卻發(fā)現(xiàn)不能在別人的電腦上啟動(dòng)程
序,其實(shí)就是陷入了使用者電腦缺少 DLL文件而無(wú)法執(zhí)行程序的窘境。有三種方法可以解決這個(gè)令人困擾的問(wèn)題:
1 . 使用者的電腦,必須先安裝「Visual C++開(kāi)發(fā)套件」(MSVC 2008 或 MSVC 2005 )。
2 . 將所需的 DLL文件,例如 MSVCR90D.dll與MSVCP90.dll,直接附在程序的下載包當(dāng)中。
3 . 以靜態(tài)鏈接方式生成程序執(zhí)行文件。
?
當(dāng)你無(wú)法確定自己的程序或別人的程序,是否相依于某些特定的 DLL文件時(shí),有一個(gè)非常好用的免費(fèi)工具程序 Dependency
Walker,可以開(kāi)啟 EXE格式的執(zhí)行文件或者 DLL格式的動(dòng)態(tài)程序庫(kù),然后詳細(xì)地條列出它們所相依的 DLL文件。
了解了幾種不同的 CRT版本選項(xiàng)之后,回到最前面的錯(cuò)誤信息問(wèn)題,相信各位現(xiàn)在應(yīng)該能夠很清楚地理解,原來(lái)會(huì)發(fā)生這些奇
怪的錯(cuò)誤狀況,是因?yàn)槌绦蛲瑫r(shí)鏈接了 LIBCMTD.lib與MSVCRTD.lib而造成函數(shù)定義版本沖突。也就是說(shuō),程序鏈接器已經(jīng)
在其中一個(gè) CRT的版本中找到所需的函數(shù)定義,但此時(shí)卻又跳出另外一位 CRT,也給了一份相同函數(shù)的實(shí)現(xiàn)版本,所以鏈接
器無(wú)法判斷應(yīng)該忽略誰(shuí)并且選擇誰(shuí)。
而這個(gè)狀況的發(fā)生原因,就是你的程序與程序所鏈接的外部程序庫(kù),使用了不同的 CRT版本之故。例如,當(dāng)你的程序使用了
Lua,自然必須鏈接至 Lua的程序庫(kù) lua5.1.lib,但如果lua5.1.lib是以靜態(tài)鏈接版本的 CRT生成而成,而你的程序卻是以預(yù)
設(shè)選項(xiàng),動(dòng)態(tài)鏈接 CRT 來(lái)生成程序執(zhí)行文件的話,如此一來(lái)就會(huì)產(chǎn)生上述這些錯(cuò)誤信息了。至此,問(wèn)題的答已昭然若揭,解
決方法有二種:
其一是將Lua重新以動(dòng)態(tài)鏈接 CRT 的方式生成出一個(gè)新的程序庫(kù);
其二則是將自己的程序項(xiàng)目改成以靜態(tài)鏈接?CRT 方式生成。
?
換個(gè)角度想,當(dāng)你身為一位程序庫(kù)的設(shè)計(jì)開(kāi)發(fā)者,想要將自己寫(xiě)的東西分享給其他人,但又不想要完全開(kāi)放自己撰寫(xiě)的程序源
碼時(shí),至少可以同時(shí)提供以下四種版本的程序庫(kù),以妥善滿(mǎn)足使用者的各種不同需求:
Debug:動(dòng)態(tài)鏈接Debug版本
Release:動(dòng)態(tài)鏈接版本
Debug_Static:靜態(tài)鏈接Debug版本
Release_Static:靜態(tài)鏈接版本
?
然而,有時(shí)候世界并不會(huì)運(yùn)作得如此理想。在某些特殊的狀況下,當(dāng)我們使用他人所寫(xiě)的第三方程序庫(kù)時(shí),有時(shí)可能只拿得到
其中某個(gè)特定的版本,例如 Release_Static版本時(shí),就很有可能會(huì)遇到程序庫(kù)沖突的錯(cuò)誤情形。此時(shí)就需要視項(xiàng)目的實(shí)際需求
而定,可以在項(xiàng)目屬性中指定「忽略特定程序庫(kù)」(Ignore Specific Library)這個(gè)選項(xiàng),讓程序代碼鏈接器忽略某些程序庫(kù),
以此化解動(dòng)靜程序庫(kù)或新舊程序庫(kù)之間的恩怨沖突。
?
小測(cè)驗(yàn):你所撰寫(xiě)的程序,必須鏈接某個(gè)以靜態(tài)多執(zhí)行線程 (/MT) CRT 生成而成的程序庫(kù)。如果你的程序在 Debug組態(tài)下以
多執(zhí)行線程偵錯(cuò) (/MTd)選項(xiàng)生成,是否會(huì)產(chǎn)生沖突?如果你的程序在 Release組態(tài)下以多執(zhí)行線程 (/MT) 選項(xiàng)生成,是否
會(huì)產(chǎn)生沖突?是的話,應(yīng)該如何解決?
上面的方法還是不行!會(huì)出現(xiàn)其他問(wèn)題的。
以下是我摸索出的最新的解決方法:
首先,所有的lib文件,使用/MTd或/MT編譯(注:即靜態(tài)鏈接模式)。Debug調(diào)試模式使用/MTd,Release模式使用/MT。
然后,在自己的程序中也使用/MTd或/MT編譯。這樣就不會(huì)出問(wèn)題了。
三種編譯鏈接庫(kù)的方式:
(1)連接Windows庫(kù)。針對(duì)Win32 API編寫(xiě)的應(yīng)用程序,上面的方法可能帶來(lái)新問(wèn)題,可以忽略libcmt.lib庫(kù),即可。如果還
有其他問(wèn)題,再忽略相應(yīng)的庫(kù)。
(2)MFC靜態(tài)鏈接。上面的方法就是針對(duì)這種鏈接方式的,所以沒(méi)問(wèn)題。
(3)MFC動(dòng)態(tài)鏈接。沒(méi)有試過(guò),應(yīng)該和(1)類(lèi)似。
最后補(bǔ)充:如果還不行,直接加入/force:multiple編譯參數(shù)吧。這次之所以沒(méi)有使用它,也是為了嚴(yán)謹(jǐn)起見(jiàn)。
轉(zhuǎn)載于:https://www.cnblogs.com/qiaojifa/p/7931858.html
總結(jié)
以上是生活随笔為你收集整理的[转]关于形如--error LNK2005: xxx 已经在 msvcrtd.lib ( MSVCR90D.dll ) 中定义--的问题分析解决...的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問(wèn)題。
- 上一篇: fiddler抓取https请求
- 下一篇: 解决Maven报Plugin execu