本文全部转自博客园用户VictoKu 原文链接:http://www.cnblogs.com/kuliuheng/p/5048832.html
今天一整天都在折腾“error LNK2001: 无法解析的外部符号”,就在头疼不已的时候,总算是找到问题原因了:各个动态链接库的编译方式必须统一才行,要不然很容易对库函数的引用产生冲突。简单来说就是,如果使用的第三方函数库编译方式采用/MD,那么主工程也应该使用/MD。我使用了libevent,而主工程默认采用/MT,所以需要忽略一大堆的函数库,我还纳闷呢,怎么会这么奇怪!!今天总算是解决了长久以来的困惑了。
下面引用一篇文章的描述:[Z]VC运行库版本不同导致链接.LIB静态库时发生重复定义问题的一个案例分析和总结
再参考一篇:msvcprt.lib(MSVCP90.dll) : error LNK2005:已经在libcpmtd.lib(xmutex.obj) 中定义
Background
MSDN中对于在不同的配置下Link的LIB作了说明:
C Runtime Library:
C++ Standard Library:
编译器会自动根据编译选项,选择对应的LIB文件。一般情况下这不会出现问题。
然而,在部分情况下,一旦你的程序的各个部分(LIB, OBJ…)并非由相同的编译选项编译出,而Link在一起的话,会出现各种各样的看似很难解决的问题,这类问题主要以重复定义的错误形式存在,通常的解决方法也很简单,就是选择同样的编译选项进行编译之后再Link。
关于链接方式补充
1、为什么选择/MD,不选/MT?
(1)程序就不需要静态链接运行时库,可以减小软件的大小;
(2)所有的模块都采用/MD,使用的是同一个堆,不存在A堆申请,B堆释放的问题;
(3)用户机器可能缺少我们编译时使用的动态运行时库。(补充:如果我们软件有多个DLL,采用/MT体积增加太多,则可以考虑/MD + 自带系统运行时库)
选择/MD要注意“多个模块选择不同版本运行库”的问题:
-
多个dll被一个exe LoadLibrary加载,如果这些dll使用的运行时库是不同的,那么可能出现加载失败,原因可能是旧版本的运行时库已经在了,而某个dll它需要的是新版本的运行时库,旧版本不符合要求。
-
如果工程里所有的模块都是自己写的或者可以完全控制的,那么这个问题不难解决,只需要在工程设置里都设置/MD,然后在相同的环境下编译一次就行。但是假如这个模块是外界提供的呢?
-
可能存在这种情况:A动态库使用了B静态库,B静态库使用了C动态库,B静态库是外界提供的,我们要使用它,但无法修改它,我们也无法接触到C动态库。如果C动态库使用的运行时库版本跟编译A动态库的本地使用的不一致,那么A动态库里的嵌入信息就会记录两个不同版本的运行时库,它被加载的时候,可能会选择版本新的。假设A动态库被一个exe LoadLibrary加载,而这个exe本身的运行时库是旧的,这样就会导致A动态库加载失败,即便把新的运行时库拷贝到目录下也不行,因为exe这个进程已经加载了那个旧的运行时库。这时候必须使用manifest文件指定嵌入到A动态库里的运行时库为某个版本,忽略掉C动态库使用的运行时库版本。
-
这个问题挺复杂的,我心思没去验证windows的PE文件加载会对运行时库做什么样的优先选择、运行时库在静态库里的记录…。只要记住,给外界使用的组件版本尽量避免使用/MD(这样会导致膨胀吗?据说,安装包可以做字节流式压缩)。
-
附上另一个问题:静态库的依赖关系:exe–>libA–>libB,现在不想让exe接触到libB,于是把libA的librarian选项–>General选项–>Link Library Dependencies设置为Yes,这样即可,libA会包含libB,exe只需要接触libA。另外需要特别注意,libA对libB的依赖只需要且只能在Solution的Project Dependencies里设置,如果在libA的代码里写了”#pragma comment(lib, “libB.lib”)”,会导致exe在link libA的时候提示找不到libA。如果exe还出现link错误,那一定是VS抽筋了:)
2、为什么选择/MT,不选择/MD?
(1)有些系统可能没有程序所需要版本的运行时库,程序必须把运行时库静态链接上。
(2)减少模块对外界的依赖。
选择/MT 时存在一个“堆空间释放”的问题:
-
不同的模块各自有一份C运行时库代码、或者根本没有C运行时库,导致了各个模块会有各自的堆。如果在A堆中申请空间,到B堆中释放就会有崩溃,在模块A申请的空间,必须在模块A中释放。
3、多个模块,必须选择相同的运行时库。
Case Study
之前刚下载了ANTLR,在准备编译它的Example的时候发现了下面的Build错误(我自己为这个例子创建了VS的项目,当前配置为动态链接Runtime库,Debug版):
1>msvcprtd.lib(MSVCP80D.dll) : error LNK2005: “public: __thiscall std::basic_string<char,struct std::char_traits,class std::allocator >::~basic_string<char,struct std::char_traits,class std::allocator >(void)” (??1?
b
a
s
i
c
s
t
r
i
n
g
@
D
U
?
basic_string@DU?
basicstring@DU?char_traits@D@std@@V?KaTeX parse error: Expected 'EOF', got '&' at position 218: …ocator<char> > &̲ __thiscall std…basic_string@DU?
c
h
a
r
t
r
a
i
t
s
@
D
@
s
t
d
@
@
V
?
char_traits@D@std@@V?
chartraits@D@std@@V?allocator@D@2@@std@@QAEAAV12@IIPBDI@Z) already defined in antlr.lib(CharScanner.obj)
1>msvcprtd.lib(MSVCP80D.dll) : error LNK2005: “public: void __thiscall std::basic_string<char,struct std::char_traits,class std::allocator >::reserve(unsigned int)” (?reserve@?
b
a
s
i
c
s
t
r
i
n
g
@
D
U
?
basic_string@DU?
basicstring@DU?char_traits@D@std@@V?KaTeX parse error: Expected group after '_' at position 144: …: unsigned int _̲_thiscall std::…basic_string@DU?
c
h
a
r
t
r
a
i
t
s
@
D
@
s
t
d
@
@
V
?
char_traits@D@std@@V?
chartraits@D@std@@V?allocator@D@2@@std@@QBEIXZ) already defined in antlr.lib(CharScanner.obj)
1>msvcprtd.lib(MSVCP80D.dll) : error LNK2005: “public: class std::basic_string<char,struct std::char_traits,class std::allocator > & __thiscall std::basic_string<char,struct std::char_traits,class std::allocator >::operator+=(class std::basic_string<char,struct std::char_traits,class std::allocator > const &)” (??Y?
b
a
s
i
c
s
t
r
i
n
g
@
D
U
?
basic_string@DU?
basicstring@DU?char_traits@D@std@@V?KaTeX parse error: Expected group after '_' at position 141: …2005: "public: _̲_thiscall std::…basic_string@DU?
c
h
a
r
t
r
a
i
t
s
@
D
@
s
t
d
@
@
V
?
char_traits@D@std@@V?
chartraits@D@std@@V?allocator@D@2@@std@@QAE@ABV01@@Z) already defined in antlr.lib(CharScanner.obj)
1>msvcprtd.lib(MSVCP80D.dll) : error LNK2005: "public: char const & __thiscall std::basic_string<char,struct std::char_traits,class std::allocator >::operator[](unsigned int)const " (??A?
b
a
s
i
c
s
t
r
i
n
g
@
D
U
?
basic_string@DU?
basicstring@DU?char_traits@D@std@@V?KaTeX parse error: Expected 'EOF', got '&' at position 221: …ocator<char> > &̲ __thiscall std…basic_string@DU?
c
h
a
r
t
r
a
i
t
s
@
D
@
s
t
d
@
@
V
?
char_traits@D@std@@V?
chartraits@D@std@@V?allocator@D@2@@std@@QAEAAV01@ABV01@@Z) already defined in antlr.lib(CharScanner.obj)
1>msvcprtd.lib(MSVCP80D.dll) : error LNK2005: “public: class std::basic_string<char,struct std::char_traits,class std::allocator > & __thiscall std::basic_string<char,struct std::char_traits,class std::allocator >::operator=(char const *)” (??4?
b
a
s
i
c
s
t
r
i
n
g
@
D
U
?
basic_string@DU?
basicstring@DU?char_traits@D@std@@V?KaTeX parse error: Expected group after '_' at position 138: …2005: "public: _̲_thiscall std::…basic_string@DU?
c
h
a
r
t
r
a
i
t
s
@
D
@
s
t
d
@
@
V
?
char_traits@D@std@@V?
chartraits@D@std@@V?allocator@D@2@@std@@QAE@PBD@Z) already defined in antlr.lib(CharScanner.obj)
1>msvcprtd.lib(MSVCP80D.dll) : error LNK2005: “class std::basic_string<char,struct std::char_traits,class std::allocator > __cdecl std::operator+<char,struct std::char_traits,class std::allocator >(class std::basic_string<char,struct std::char_traits,class std::allocator > const &,class std::basic_string<char,struct std::char_traits,class std::allocator > const &)” (??
?
H
D
U
?
?HDU?
?HDU?char_traits@D@std@@V?
a
l
l
o
c
a
t
o
r
@
D
@
1
@
@
s
t
d
@
@
Y
A
?
A
V
?
allocator@D@1@@std@@YA?AV?
allocator@D@1@@std@@YA?AV?basic_string@DU?
c
h
a
r
t
r
a
i
t
s
@
D
@
s
t
d
@
@
V
?
char_traits@D@std@@V?
chartraits@D@std@@V?allocator@D@2@@0@ABV10@0@Z) already defined in antlr.lib(MismatchedCharException.obj)
1>msvcprtd.lib(MSVCP80D.dll) : error LNK2005: "public: char const * __thiscall std::basic_string<char,struct std::char_traits,class std::allocator >::c_str(void)const " (?c_str@?
b
a
s
i
c
s
t
r
i
n
g
@
D
U
?
basic_string@DU?
basicstring@DU?char_traits@D@std@@V?KaTeX parse error: Expected group after '_' at position 129: …LNK2005: "bool _̲_cdecl std::ope…?MDU?
c
h
a
r
t
r
a
i
t
s
@
D
@
s
t
d
@
@
V
?
char_traits@D@std@@V?
chartraits@D@std@@V?allocator@D@1@@std@@YA_NABV?
b
a
s
i
c
s
t
r
i
n
g
@
D
U
?
basic_string@DU?
basicstring@DU?char_traits@D@std@@V?KaTeX parse error: Expected 'EOF', got '&' at position 186: …traits<char> > &̲ __thiscall std…basic_ostream@DU?KaTeX parse error: Expected 'EOF', got '&' at position 219: …traits<char> > &̲ __thiscall std…basic_ostream@DU?KaTeX parse error: Expected 'EOF', got '&' at position 195: …traits<char> > &̲ __cdecl std::e…basic_ostream@DU?KaTeX parse error: Expected group after '_' at position 139: … "public: void _̲_thiscall std::…basic_ios@DU?KaTeX parse error: Expected group after '_' at position 142: …: "public: int _̲_thiscall std::…basic_streambuf@DU?KaTeX parse error: Expected group after '_' at position 151: …c: static bool _̲_cdecl std::cha…char_traits@D@std@@SA_NABH0@Z) already defined in antlr.lib(CharScanner.obj)
1>msvcprtd.lib(MSVCP80D.dll) : error LNK2005: “public: static int __cdecl std::char_traits::eof(void)” (?eof@?KaTeX parse error: Expected group after '_' at position 132: …: "public: int _̲_thiscall std::…basic_streambuf@DU?KaTeX parse error: Expected group after '_' at position 202: …aits<char> > * _̲_thiscall std::…basic_ios@DU?
c
h
a
r
t
r
a
i
t
s
@
D
@
s
t
d
@
@
@
s
t
d
@
@
Q
B
E
P
A
V
?
char_traits@D@std@@@std@@QBEPAV?
chartraits@D@std@@@std@@QBEPAV?basic_streambuf@DU?KaTeX parse error: Expected group after '_' at position 133: … "public: char _̲_thiscall std::…basic_ios@DU?KaTeX parse error: Expected group after '_' at position 139: …: "public: int _̲_thiscall std::…char_traits@D@std@@SAIPBD@Z) already defined in antlr.lib(CharScanner.obj)
1>msvcprtd.lib(MSVCP80D.dll) : error LNK2005: “public: class std::basic_ostream<char,struct std::char_traits > & __thiscall std::basic_ostream<char,struct std::char_traits >::flush(void)” (?flush@?
b
a
s
i
c
o
s
t
r
e
a
m
@
D
U
?
basic_ostream@DU?
basicostream@DU?char_traits@D@std@@@std@@QAEAAV12@XZ) already defined in antlr.lib(CharScanner.obj)
1>msvcprtd.lib(MSVCP80D.dll) : error LNK2005: "public: class std::basic_ostream<char,struct std::char_traits > * __thiscall std::basic_ios<char,struct std::char_traits >::tie(void)const " (?tie@?
b
a
s
i
c
i
o
s
@
D
U
?
basic_ios@DU?
basicios@DU?char_traits@D@std@@@std@@QBEPAV?
b
a
s
i
c
o
s
t
r
e
a
m
@
D
U
?
basic_ostream@DU?
basicostream@DU?char_traits@D@std@@@2@XZ) already defined in antlr.lib(CharScanner.obj)
1>msvcprtd.lib(MSVCP80D.dll) : error LNK2005: "public: bool __thiscall std::ios_base::good(void)const " (?good@ios_base@std@@QBE_NXZ) already defined in antlr.lib(CharScanner.obj)
1>msvcprtd.lib(MSVCP80D.dll) : error LNK2005: “public: void __thiscall std::basic_ostream<char,struct std::char_traits >::_Osfx(void)” (?_Osfx@?
b
a
s
i
c
o
s
t
r
e
a
m
@
D
U
?
basic_ostream@DU?
basicostream@DU?char_traits@D@std@@@std@@QAEXXZ) already defined in antlr.lib(CharScanner.obj)
1>msvcprtd.lib(MSVCP80D.dll) : error LNK2005: “public: void __thiscall std::basic_streambuf<char,struct std::char_traits >::_Lock(void)” (?_Lock@?
b
a
s
i
c
s
t
r
e
a
m
b
u
f
@
D
U
?
basic_streambuf@DU?
basicstreambuf@DU?char_traits@D@std@@@std@@QAEXXZ) already defined in antlr.lib(CharScanner.obj)
1>msvcprtd.lib(MSVCP80D.dll) : error LNK2005: “public: void __thiscall std::basic_streambuf<char,struct std::char_traits >::_Unlock(void)” (?_Unlock@?
b
a
s
i
c
s
t
r
e
a
m
b
u
f
@
D
U
?
basic_streambuf@DU?
basicstreambuf@DU?char_traits@D@std@@@std@@QAEXXZ) already defined in antlr.lib(CharScanner.obj)
1>msvcprtd.lib(MSVCP80D.dll) : error LNK2005: “class std::basic_ostream<char,struct std::char_traits > & __cdecl std::operator<<<char,struct std::char_traits,class std::allocator >(class std::basic_ostream<char,struct std::char_traits > &,class std::basic_string<char,struct std::char_traits,class std::allocator > const &)” (??
?
6
D
U
?
?6DU?
?6DU?char_traits@D@std@@V?
a
l
l
o
c
a
t
o
r
@
D
@
1
@
@
s
t
d
@
@
Y
A
A
A
V
?
allocator@D@1@@std@@YAAAV?
allocator@D@1@@std@@YAAAV?basic_ostream@DU?
c
h
a
r
t
r
a
i
t
s
@
D
@
s
t
d
@
@
@
0
@
A
A
V
10
@
A
B
V
?
char_traits@D@std@@@0@AAV10@ABV?
chartraits@D@std@@@0@AAV10@ABV?basic_string@DU?
c
h
a
r
t
r
a
i
t
s
@
D
@
s
t
d
@
@
V
?
char_traits@D@std@@V?
chartraits@D@std@@V?allocator@D@2@@0@@Z) already defined in antlr.lib(LLkParser.obj)
1>libcpmt.lib(locale0.obj) : error LNK2005: “private: static class std::locale::_Locimp * __cdecl std::locale::_Getgloballocale(void)” (?_Getgloballocale@locale@std@@CAPAV_Locimp@12@XZ) already defined in msvcprtd.lib(MSVCP80D.dll)
1>libcpmt.lib(locale0.obj) : error LNK2005: “private: static void __cdecl std::locale::facet::facet_Register(class std::locale::facet *)” (?facet_Register@facet@locale@std@@CAXPAV123@@Z) already defined in msvcprtd.lib(MSVCP80D.dll)
1>libcpmt.lib(locale0.obj) : error LNK2005: “public: static void __cdecl std::_Locinfo::_Locinfo_dtor(class std::_Locinfo *)” (?_Locinfo_dtor@_Locinfo@std@@SAXPAV12@@Z) already defined in msvcprtd.lib(MSVCP80D.dll)
1>libcpmt.lib(locale0.obj) : error LNK2005: “public: static void __cdecl std::_Locinfo::_Locinfo_ctor(class std::_Locinfo *,char const *)” (?_Locinfo_ctor@_Locinfo@std@@SAXPAV12@PBD@Z) already defined in msvcprtd.lib(MSVCP80D.dll)
1>libcpmt.lib(xmutex.obj) : error LNK2005: “public: void __thiscall std::_Mutex::_Lock(void)” (?_Lock@_Mutex@std@@QAEXXZ) already defined in msvcprtd.lib(MSVCP80D.dll)
1>libcpmt.lib(xmutex.obj) : error LNK2005: “public: void __thiscall std::_Mutex::_Unlock(void)” (?_Unlock@_Mutex@std@@QAEXXZ) already defined in msvcprtd.lib(MSVCP80D.dll)
1>libcpmt.lib(xlock.obj) : error LNK2005: “public: __thiscall std::_Lockit::_Lockit(int)” (??0_Lockit@std@@QAE@H@Z) already defined in msvcprtd.lib(MSVCP80D.dll)
1>libcpmt.lib(xlock.obj) : error LNK2005: “public: __thiscall std::_Lockit::~_Lockit(void)” (??1_Lockit@std@@QAE@XZ) already defined in msvcprtd.lib(MSVCP80D.dll)
1>LIBCMT.lib(invarg.obj) : error LNK2005: __invoke_watson already defined in MSVCRTD.lib(MSVCR80D.dll)
1>LIBCMT.lib(invarg.obj) : error LNK2005: __invalid_parameter already defined in MSVCRTD.lib(MSVCR80D.dll)
1>LIBCMT.lib(setlocal.obj) : error LNK2005: __configthreadlocale already defined in MSVCRTD.lib(MSVCR80D.dll)
1>LIBCMT.lib(tidtable.obj) : error LNK2005: __encode_pointer already defined in MSVCRTD.lib(MSVCR80D.dll)
1>LIBCMT.lib(tidtable.obj) : error LNK2005: __decode_pointer already defined in MSVCRTD.lib(MSVCR80D.dll)
1>LIBCMT.lib(tolower.obj) : error LNK2005: _tolower already defined in MSVCRTD.lib(MSVCR80D.dll)
1>LIBCMT.lib(crt0dat.obj) : error LNK2005: __amsg_exit already defined in MSVCRTD.lib(MSVCR80D.dll)
1>LIBCMT.lib(crt0dat.obj) : error LNK2005: __initterm_e already defined in MSVCRTD.lib(MSVCR80D.dll)
1>LIBCMT.lib(crt0dat.obj) : error LNK2005: _exit already defined in MSVCRTD.lib(MSVCR80D.dll)
1>LIBCMT.lib(crt0dat.obj) : error LNK2005: __exit already defined in MSVCRTD.lib(MSVCR80D.dll)
1>LIBCMT.lib(crt0dat.obj) : error LNK2005: __cexit already defined in MSVCRTD.lib(MSVCR80D.dll)
1>LIBCMT.lib(lconv.obj) : error LNK2005: _localeconv already defined in MSVCRTD.lib(MSVCR80D.dll)
1>LIBCMT.lib(mlock.obj) : error LNK2005: __unlock already defined in MSVCRTD.lib(MSVCR80D.dll)
1>LIBCMT.lib(mlock.obj) : error LNK2005: __lock already defined in MSVCRTD.lib(MSVCR80D.dll)
1>LIBCMT.lib(winxfltr.obj) : error LNK2005: __XcptFilter already defined in MSVCRTD.lib(MSVCR80D.dll)
1>LIBCMT.lib(crt0init.obj) : error LNK2005: ___xi_a already defined in MSVCRTD.lib(cinitexe.obj)
1>LIBCMT.lib(crt0init.obj) : error LNK2005: ___xi_z already defined in MSVCRTD.lib(cinitexe.obj)
1>LIBCMT.lib(crt0init.obj) : error LNK2005: ___xc_a already defined in MSVCRTD.lib(cinitexe.obj)
1>LIBCMT.lib(crt0init.obj) : error LNK2005: ___xc_z already defined in MSVCRTD.lib(cinitexe.obj)
1>LIBCMT.lib(hooks.obj) : error LNK2005: “void __cdecl terminate(void)” (?terminate@@YAXXZ) already defined in MSVCRTD.lib(MSVCR80D.dll)
1>LIBCMT.lib(crt0.obj) : error LNK2005: _mainCRTStartup already defined in MSVCRTD.lib(crtexe.obj)
1>LIBCMT.lib(errmode.obj) : error LNK2005: ___set_app_type already defined in MSVCRTD.lib(MSVCR80D.dll)
1>LIBCMT.lib(_ctype.obj) : error LNK2005: _isprint already defined in MSVCRTD.lib(MSVCR80D.dll)
1>MSVCRTD.lib(MSVCR80D.dll) : error LNK2005: __stricmp already defined in LIBCMT.lib(stricmp.obj)
1>LINK : warning LNK4098: defaultlib ‘MSVCRTD’ conflicts with use of other libs; use /NODEFAULTLIB:library
1>LINK : warning LNK4098: defaultlib ‘LIBCMT’ conflicts with use of other libs; use /NODEFAULTLIB:library
1>D:\home\doc\Visual Studio 2005\Projects\tst_antlr_3\Debug\tst_antlr_3.exe : fatal error LNK1169: one or more multiply defined symbols found
分析一下错误来源,会发现:
错误来源主要是重复定义的问题,而且重复定义的基本上都是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就是最好的例子。