LNK2005 LNK1169 Error and LNK4098 Warning
作者:童磊(magictong)
静态库冲突的根源:
YY一下链接器的工作方式
此处省略800字……
指定链接时的运行时库:
各编译选项对应的库情况:
编译选项 |
CRT |
CPPRT |
说明 |
/ML |
libc.lib |
|
单线程库 |
/MLd |
libcd.lib |
|
单线程调试库 |
/MT |
libcmt.lib |
libcpmt.lib |
多线程静态库 |
/MTd |
libcmtd.lib |
libcpmtd.lib |
多线程静态调试库 |
/MD |
msvcrt.lib(msvcrt.dll) |
msvcprt.lib(msvcprt.dll) |
多线程动态库 |
/MDd |
msvcrtd.lib(msvcrtd.dll) |
msvcprtd.lib(msvcprtd.dll) |
多线程动态调试库 |
一般来说编译器会根据编译选项自动选择对应的标准库。
例子说明(暴露问题)
---------------------------------------------------------------------------------------------------------------------------------
情景一:
app: MT
lib: MD
LIBCMT.lib(crt0init.obj) : warning LNK4098: defaultlib 'msvcrt.lib' conflicts with use of other libs; use /NODEFAULTLIB:library
因为你显式指定的标准库版本与目标文件的缺省值不一致。通常来说,应该保证链接器合并的所有目标文件指定的缺省标准库版本一致,否则编译器一定会给出上面的警告
情景二:
app: MD
lib: MT
MSVCRT.lib(cinitexe.obj) : warning LNK4098: defaultlib 'libcmt.lib' conflicts with use of other libs; use /NODEFAULTLIB:library
情景三:
app: MD
lib: MDd
MSVCRT.lib(cinitexe.obj) : warning LNK4098: defaultlib 'msvcrtd.lib' conflicts with use of other libs; use /NODEFAULTLIB:library
情景四:
app: MT
lib: MTd
lib中使用了
#include <crtdbg.h>
_malloc_dbg(1, _NORMAL_BLOCK, __FILE__, __LINE__);
1>Linking...
1>libcmtd.lib(dbgheap.obj) : error LNK2005: _malloc already defined in LIBCMT.lib(malloc.obj)
1>libcmtd.lib(dbgheap.obj) : error LNK2005: __heap_alloc already defined in LIBCMT.lib(malloc.obj)
1>libcmtd.lib(dbgheap.obj) : error LNK2005: _calloc already defined in LIBCMT.lib(calloc.obj)
1>libcmtd.lib(dbgheap.obj) : error LNK2005: _realloc already defined in LIBCMT.lib(realloc.obj)
1>libcmtd.lib(dbgheap.obj) : error LNK2005: __recalloc already defined in LIBCMT.lib(realloc.obj)
1>libcmtd.lib(dbgheap.obj) : error LNK2005: _free already defined in LIBCMT.lib(free.obj)
1>libcmtd.lib(dbgheap.obj) : error LNK2005: __msize already defined in LIBCMT.lib(msize.obj)
1>libcmtd.lib(malloc.obj) : error LNK2005: _V6_HeapAlloc already defined in LIBCMT.lib(malloc.obj)
1>libcmtd.lib(dbghook.obj) : error LNK2005: __crt_debugger_hook already defined in LIBCMT.lib(dbghook.obj)
1>libcmtd.lib(sbheap.obj) : error LNK2005: ___sbh_pHeaderDefer already defined in LIBCMT.lib(sbheap.obj)
1>libcmtd.lib(sbheap.obj) : error LNK2005: __set_sbh_threshold already defined in LIBCMT.lib(sbheap.obj)
1>libcmtd.lib(sbheap.obj) : error LNK2005: __set_amblksiz already defined in LIBCMT.lib(sbheap.obj)
1>libcmtd.lib(sbheap.obj) : error LNK2005: __get_amblksiz already defined in LIBCMT.lib(sbheap.obj)
1>libcmtd.lib(sbheap.obj) : error LNK2005: ___sbh_heap_init already defined in LIBCMT.lib(sbheap.obj)
1>libcmtd.lib(sbheap.obj) : error LNK2005: ___sbh_find_block already defined in LIBCMT.lib(sbheap.obj)
1>libcmtd.lib(sbheap.obj) : error LNK2005: ___sbh_free_block already defined in LIBCMT.lib(sbheap.obj)
1>libcmtd.lib(sbheap.obj) : error LNK2005: ___sbh_alloc_block already defined in LIBCMT.lib(sbheap.obj)
1>libcmtd.lib(sbheap.obj) : error LNK2005: ___sbh_alloc_new_region already defined in LIBCMT.lib(sbheap.obj)
1>libcmtd.lib(sbheap.obj) : error LNK2005: ___sbh_alloc_new_group already defined in LIBCMT.lib(sbheap.obj)
1>libcmtd.lib(sbheap.obj) : error LNK2005: ___sbh_resize_block already defined in LIBCMT.lib(sbheap.obj)
1>libcmtd.lib(sbheap.obj) : error LNK2005: ___sbh_heapmin already defined in LIBCMT.lib(sbheap.obj)
1>libcmtd.lib(sbheap.obj) : error LNK2005: ___sbh_heap_check already defined in LIBCMT.lib(sbheap.obj)
1>libcmtd.lib(isctype.obj) : error LNK2005: __isctype_l already defined in LIBCMT.lib(isctype.obj)
1>libcmtd.lib(isctype.obj) : error LNK2005: __isctype already defined in LIBCMT.lib(isctype.obj)
1>LIBCMT.lib(crt0init.obj) : warning LNK4098: defaultlib 'libcmtd.lib' conflicts with use of other libs; use /NODEFAULTLIB:library
1>H:\prj\CRTSetting\LibLoader\Release\LibLoader.exe : fatal error LNK1169: one or more multiply defined symbols found
解决方案:
· 我们在编程的时候,一定要把所有的工程的编译选项配置成一样的(主要是静态库和引用静态库的工程的,debug对应debug,release对应release的,一一对应)。
· 如果部分LIB是由第三方提供的怎么办?,譬如我们引用了zlib的静态库(一般第三方发布的静态库都有多个版本),这种情况下一般只能调整自己的编译选项,或者可能使用Ignore Specific Library 编译选项能解决问题,但是根据上面做的实验我们知道这种方法不能解决所有问题(关于Ignore Specific Library的用法可以参见链接:http://blog.csdn.net/magictong/archive/2010/12/29/6105160.aspx)。
· 如果我们发布静态LIB库给别人使用,最好对应不同的编译选项,甚至不同的vs版本,提供不同版本的LIB。
Ignore Specific Library Table
使用下面的运行时库 |
需要忽略的库 |
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 |