今天在調試發布一個Windows 8游戲版本時發現這個異常:
Error 1 : error LNK2005: _exit already defined in msvcrt.lib(MSVCR100.dll) LIBCMTD.lib SampleGame
剛開始在開發Debug時並沒有出現過這樣問題.當嘗試發布一個新版本.構建Realse 包時.於是乎就超過75個 Lnk2005 Error出現List中:
ok.這樣瞬間就爆發了75個基本類同的錯誤.首先看了MS官方對這個錯誤定義:Linker Tools Error LNK2005.可見LNK在C++編程時常見的.一個重復定義的錯誤.那么總結一下官方針對這個Error定義出現的三種情況如下:
A:頭文件重復包含.
在頭文件中常常包含具有變量 函數 和類定義的. 但是問題是如果頭文件在相關宏等相關的重復鏈接處理措施.就會到時重復引用.
B:重復定義全局變量
這個應該就不用多說了.全局變量時針對整個工程的 .正確做法應該在一個Cpp文件中定義.類似:
1: int test_datatag
那么使用調用的方法就應該為:
1: extern int test_datatag
如果還繼續使用test_datatag則會立即爆出異常:
ObjError LNK2005 in index.cpp test_datatag already defined in index.obj
C:引用第三方庫.
這種情況比較普遍.主要是因為C Run time 函數庫和MFC庫存在沖突照成的.在目前的VC對C Runtime 運行時庫總共有6種:
Single-threaded (libc.lib) libcmt.lib, msvcrt.lib, libcd.lib, libcmtd.lib, msvcrtd.lib
Multithreaded (libcmt.lib) libc.lib, msvcrt.lib, libcd.lib, libcmtd.lib, msvcrtd.lib
Multithreaded using DLL (msvcrt.lib) libc.lib, libcmt.lib, libcd.lib, libcmtd.lib, msvcrtd.lib
Debug Single-threaded (libcd.lib) libc.lib, libcmt.lib, msvcrt.lib, libcmtd.lib, msvcrtd.lib
Debug Multithreaded (libcmtd.lib) libc.lib, libcmt.lib, msvcrt.lib, libcd.lib, msvcrtd.lib
Debug Multithreaded using DLL (msvcrtd.lib) libc.lib, libcmt.lib, msvcrt.lib, libcd.lib, libcmtd.lib
如果我們項目中引用不同的C函數庫. 微軟針對C有兩種C函數庫.一種是普通的函數庫:LIBC.LIB.格式/.特點是不支持多線程.另外一種是支持多線程的MSVCRT.lib.如果在一個工程中混合使用這兩種函數庫.則很容易導致LNK2005錯誤.一般情況下不推薦混合使用.如果真的有實際需求.最好處理方式采用MFC先C run time函數庫link鏈接.因此推薦使用支持多線程的msvcrt.lib.
C run time 運行時函數包如下庫:
當引用第三方庫時很容易出現這種錯誤.例如boot和WXWindow使用MD來編譯.也就是上面提到支持多線程的C runtime 函數庫.這時如果我們編輯自己項目沒有指明/MD 來編譯.就會導致兩種C函數出現沖突.並且在編譯時導致大量的LNK2005錯誤.
來看一下關於C run time 函數庫編譯形式常用如下:
說到這大概明白項目在Realse時大批量出現Error LNK2005原因.也就是因為引用庫導致的.現在看看目前項目中C/C++編譯設置: 打開項目在Properties->C/C++->All Options中找到Runtime Libraty值
可見為MD.
so.說了這么多搞清楚問題所在.如果Fix這個問題.
根據官方對着這個問題提出解決方案如下:
首先打開項目Properties->Configuration Properties->Linker中如果我們引用會看到對應的庫會看到對應的值:
這個問題是因為兩個庫之間存在沖突引起,.的.可以發現沖突出現LIBCMD.lib中.官方給出做法也相當的簡單直接.可以再項目直接忽略對該函數庫的引用:可以Ignore Specific Libraies設置對應的值:
設置保存后.重寫Rebuild 項目.發現所有錯誤全部沒有了.只是存在一定警告.,編譯完全通過.當然這種方式雖然簡單但顯得比較粗暴.因為libcmtd 這個庫有時候不能忽略,忽略后會有不能解析的外部符號錯誤.會導致有些運行時Run time 異常拋出.整個應用程序crash掉.
當然這種方式依然無法排除另外一種情況.
當C運行時[CRT]庫和MS基礎類MFC庫鏈接、順序有誤是.同樣也會導致LNK2005錯誤.主要是因為CRT庫對new、Delete、DllMain函數使用弱外部鏈接方式.MFC庫也包含了new、Delete、DllMain函數定義.這些函數要求先鏈接MFC庫然后再鏈接CRT庫.
完整解決方式采用強制鏈接器做法按照正確順序鏈接.通過在Properties-Configuration Properties->Linker->Command Line設置參數: /FORCE:MULTIPLE -關於該操作操作請參考官方文檔 Force Multiple
其實問題關鍵在於兩遍引用庫在進行編譯時設置必須相同才能REalse正常引用.當然相對更簡單的方式.逐個對引用項目進行對應Md編譯.然后重新添加Linker鏈接關系.這種方法雖然耗時但解決問題最為直接.也算是比較快捷方式之一.
設置完成發現項目正常編譯通過.
參考資料: