VC運行庫版本不同導致鏈接.LIB靜態庫時發生重復定義問題的一個案例分析和總結
MSDN中對於在不同的配置下Link的LIB作了說明:
C Runtime Library:
開關 |
對應的庫 |
版本 |
/MD |
MSVCRT.LIB |
多線程DLL的Release版本 |
/MDd |
MSVCRTD.LIB |
多線程DLL的Debug版本 |
/MT |
LIBCMT.LIB |
多線程靜態鏈接的Release版本 |
/MTd |
LIBCMTD.LIB |
多線程靜態鏈接的Debug版本 |
/clr |
MSVCMRT.LIB |
托管代碼和非托管代碼混合 |
/clr:pure |
MSVCURT.LIB |
純托管代碼 |
C++ Standard Library:
開關 |
對應的庫 |
版本 |
/MD |
MSVCPRT.LIB |
多線程DLL的Release版本 |
/MDd |
MSVCPRTD.LIB |
多線程DLL的Debug版本 |
/MT |
LIBCPMT.LIB |
多線程靜態鏈接的Release版本 |
/MTd |
LIBCPMTD.LIB |
多線程靜態鏈接的Debug版本 |
編譯器會自動根據編譯選項,選擇對應的LIB文件。一般情況下這不會出現問題。
然而,在部分情況下,一旦你的程序的各個部分(LIB, OBJ…)並非由相同的編譯選項編譯出,而Link在一起的話,會出現各種各樣的看似很難解決的問題,這類問題主要以重復定義的錯誤形式存在,通常的解決方法也很簡單,就是選擇同樣的編譯選項進行編譯之後再Link。
......................
- 錯誤來源主要是重復定義的問題,而且重復定義的基本上都是VC Runtime和Standard C++ Library中的函數
- LIBCMT和LIBCPMT為Release下的Lib,本來不應該出現在Debug版本的鏈接的Lib中
- 重復定義的問題主要出現在:LIBCMT, LIBCPMT, MSVCPRTD, MSVCRTD
來看看出問題的LIB是那些:
- LIBCMT:C Runtime庫的多線程靜態鏈接的Release版本
- LIBCPMT:C++ Standard Library的多線程靜態鏈接的Release版本
- MSVCPRTD:C++ Standard Library的多線程DLL的Debug版本
- MSVCRTD:C Runtime Library的多線程DLL的Debug版本
當前我們的配置是多線程DLL的Debug版,因此3和4是應該出現在link的列表中的,不屬於多余。而後兩者則是只是當多線程靜態鏈接Release版中才會出現。這提示我在項目中加入的ANTLR.LIB可能是造成這個問題的根源,因為靜態庫的編譯選項很容易和主程序發生沖突,並且根據實際信息我們可以看出ANTLR.LIB應該是用多線程靜態鏈接的Release版本來編譯的。
這樣,解決方法就很清楚了:
- 切換到Release,因為ANTLR.LIB是在Release下面編譯的
- 把Run Time庫的版本修改成多線程靜態鏈接
做了這兩個修改之後編譯通過。
還有一種方法是,自己用多線程DLL的Debug版重新編譯一次ANTLR,生成一個新的ANTLRD.LIB,再link這個Lib也可以解決這個問題。
Summary
- 知道各個不同的LIB代表的版本信息非常重要,可以幫助快速定位問題
- 在編程的時候,一定要把所有的項目的編譯選項(是靜態鏈接Runtime庫還是動態鏈接Runtime庫,Debug/Release)配置成一樣的。如果部分LIB/OBJ是由第三方提供(OBJ情況很少見),一般情況下只能調整自己的編譯選項,除非你可以要求第三方提供其他版本的編譯好的LIB
- 在發布可重用的靜態LIB庫供其他人調用的時候,最好對應不同的編譯選項,乃至VC版本,提供不同版本的LIB。VC自己的Runtime就是最好的例子。
VC運行庫版本不同導致鏈接.LIB靜態庫時發生重復定義問題的一個案例分析和總結