赞助

visual studio运行时库MT、MTd、MD、MDd的研究(转载)

转载:http://blog.csdn.net/ybxuwei/article/details/9095067

转载:http://blog.sina.com.cn/s/blog_624485f70100rp2l.html

转载:https://blog.csdn.net/jigetage/article/details/80619386

1.

在开发window程序是经常会遇到编译好好的程序拿到另一台机器上面无法运行的情况,这一般是由于另一台机器上面没有安装相应的运行时库导致的,那么这个与编译选项MT、MTd、MD、MDd有什么关系呢?这是msdn上面的解释:

MT:mutithread,多线程库,编译器会从运行时库里面选择多线程静态连接库来解释程序中的代码,即连接LIBCMT.lib库

MTd:mutithread+debug,多线程调试版,连接LIBMITD.lib库

MD:MT+DLL,多线程动态库,连接MSVCRT.lib库,这是个导入库,对应动态库为MSVCRT.dll

MDd: MT+DLL+debug,多线程动态调试库,连接MSVCRTD.lib库,对应动态库为MSVCRTD.dll

开发多线程程序时(单线程本文不做讨论),需要选择MT、MTd、MD、MDd其中的一个。

 

对于MT/MTd,由于连接运行时库是LIBCMT.lib/LIBCMTD.lib,这两个库是静态库,所以此种方式编译的程序,移到另一台机器上面也可以正常运行。

但是对于MD/MDd,连接的是动态库,所以如果另一台机器上没有MSVCRT.dll/MSVCRTD.dll时,就提示缺少动态库这样的错误。

 

曾经犯这样的错误,以为以MT/MTd方式编译,程序对所有的库都是静态链接的,其实错了,它只能决定运行时库是动态链接还是静态链接,对用户自己写的库或其他第三方库,其连接方式取决于代码(显式连接动态库Loadlibrary)或所提供的lib文件(为导入库还是静态库),移动程序到别的机器上时,还是要带上所需要的动态库的。

来看一个例子,编译一个静态库和一个动态库,均实现两个整数相加的功能:

 

1 // adds.h
2 // add后面加个s代表静态库
3 #pragma once
4 int add(int,int);
1 // adds.cpp
2 // 静态库
3 #include "adds.h"
4 int add(int a, int b)
5 {
6     return a+b;
7 }
8 以上,运行时库选择MTd,编译成静态库adds.lib
1 // addd.h
2 // add后面加d代表动态库
3 #pragma once
4 #ifndef MYLIB_API
5 #define MYLIB_API _declspec(dllexport)
6 #endif
7 
8 MYLIB_API int  add(int,int);
1 // addd.cpp
2 // 动态库
3 #include "addd.h"
4 int add(int a, int b)
5 {
6   return a+b;
7 }以上,运行时库选择MTd,编译成动态库addd.lib, addd.dll
 1 // test.cpp
 2 // 测试程序
 3 #include <iostream>
 4 
 5 // 测试静态库,此处为1,测试动态库,此处为0
 6 #define TEST_STATIC_LINK 1
 7 
 8 #if TEST_STATIC_LINK 
 9   #include <adds.h>
10 #else
11   #define MYLIB_API _declspec(dllimport)
12   #include "addd.h"
13 #endif
14 
15 using namespace std;
16 
17 int main()
18 {
19     cout << add(2,3) << endl;
20     return 0;
21 }测试程序以MTd编译

1. 测试静态库,TEST_STATIC_LINK 定义为1,提供adds.lib,生成可执行文件,移动到另一台机器上可以运行,因为测试程序和adds.lib均静态连接运行时库

2. 测试动态库,TEST_STATIC_LINK 定义为0,提供addd.lib,生成可执行文件,移动到另一台机器上可以运行,但需要addd.dll,因为addd库静态连接运行时库,测试程序静态连接运行时库,动态连接addd库

 

在上面的例子中add库和测试程序均选择MTd运行时库,若不一致会导致一些编译连接错误,让新手不着头脑。

比如adds选择MDd,连接将会出现这样的错误:

1>正在链接...

1>MSVCRTD.lib(ti_inst.obj) : error LNK2005: "private: __thiscall type_info::type_info(class type_info const &)" (??0type_info@@AAE@ABV0@@Z) 已经在LIBCMTD.lib(typinfo.obj) 中定义

1>MSVCRTD.lib(ti_inst.obj) : error LNK2005: "private: class type_info & __thiscall type_info::operator=(class type_info const &)" (??4type_info@@AAEAAV0@ABV0@@Z) 已经在LIBCMTD.lib(typinfo.obj) 中定义

即一个程序中混合了不同的运行时库(静态库和动态库,调试库和非调试库),可能会产生冲突,所以一个程序中应该使用相同的运行时库。

引用资料:http://msdn.microsoft.com/en-us/library/2kzt1wy3(v=vs.71).aspx

 

2.

遇到以下编译问题:

1>msvcprtd.lib(MSVCP90D.dll) : error LNK2005: "public: class std::basic_ostream<char,struct std::char_traits<char> > & __thiscall std::basic_ostream<char,struct std::char_traits<char> >::operator<<(class std::basic_ostream<char,struct std::char_traits<char> > & (__cdecl*)(class std::basic_ostream<char,struct std::char_traits<char> > &))" (??6?$basic_ostream@DU?$char_traits@D@std@@@std@@QAEAAV01@P6AAAV01@AAV01@@Z@Z) already defined in GFTQuantLib.lib(hiddenyieldcurve.obj)
1>msvcprtd.lib(MSVCP90D.dll) : error LNK2005: "class std::basic_ostream<char,struct std::char_traits<char> > & __cdecl std::endl(class std::basic_ostream<char,struct std::char_traits<char> > &)" (?endl@std@@YAAAV?$basic_ostream@DU?$char_traits@D@std@@@1@AAV21@@Z) already defined in GFTQuantLib.lib(hiddenyieldcurve.obj)
1>msvcprtd.lib(MSVCP90D.dll) : error LNK2005: "public: void __thiscall std::basic_ios<char,struct std::char_traits<char> >::setstate(int,bool)" (?setstate@?$basic_ios@DU?$char_traits@D@std@@@std@@QAEXH_N@Z) already defined in GFTQuantLib.lib(date.obj)
1>msvcprtd.lib(MSVCP90D.dll) : error LNK2005: "public: int __thiscall std::ios_base::width(int)" (?width@ios_base@std@@QAEHH@Z) already defined in GFTQuantLib.lib(date.obj)
1>msvcprtd.lib(MSVCP90D.dll) : error LNK2005: "public: int __thiscall std::basic_streambuf<char,struct std::char_traits<char> >::sputn(char const *,int)" (?sputn@?$basic_streambuf@DU?$char_traits@D@std@@@std@@QAEHPBDH@Z) already defined in GFTQuantLib.lib(date.obj)
1>msvcprtd.lib(MSVCP90D.dll) : error LNK2005: "public: static bool __cdecl std::char_traits<char>::eq_int_type(int const &,int const &)" (?eq_int_type@?$char_traits@D@std@@SA_NABH0@Z) already defined in GFTQuantLib.lib(date.obj)
1>msvcprtd.lib(MSVCP90D.dll) : error LNK2005: "public: static int __cdecl std::char_traits<char>::eof(void)" (?eof@?$char_traits@D@std@@SAHXZ) already defined in GFTQuantLib.lib(date.obj)
1>msvcprtd.lib(MSVCP90D.dll) : error LNK2005: "public: int __thiscall std::basic_streambuf<char,struct std::char_traits<char> >::sputc(char)" (?sputc@?$basic_streambuf@DU?$char_traits@D@std@@@std@@QAEHD@Z) already defined in GFTQuantLib.lib(date.obj)
1>msvcprtd.lib(MSVCP90D.dll) : error LNK2005: "public: class std::basic_streambuf<char,struct std::char_traits<char> > * __thiscall std::basic_ios<char,struct std::char_traits<char> >::rdbuf(void)const " (?rdbuf@?$basic_ios@DU?$char_traits@D@std@@@std@@QBEPAV?$basic_streambuf@DU?$char_traits@D@std@@@2@XZ) already defined in GFTQuantLib.lib(date.obj)
1>msvcprtd.lib(MSVCP90D.dll) : error LNK2005: "public: char __thiscall std::basic_ios<char,struct std::char_traits<char> >::fill(void)const " (?fill@?$basic_ios@DU?$char_traits@D@std@@@std@@QBEDXZ) already defined in GFTQuantLib.lib(date.obj)
1>msvcprtd.lib(MSVCP90D.dll) : error LNK2005: "public: int __thiscall std::ios_base::flags(void)const " (?flags@ios_base@std@@QBEHXZ) already defined in GFTQuantLib.lib(date.obj)
1>msvcprtd.lib(MSVCP90D.dll) : error LNK2005: "public: int __thiscall std::ios_base::width(void)const " (?width@ios_base@std@@QBEHXZ) already defined in GFTQuantLib.lib(date.obj)
1>msvcprtd.lib(MSVCP90D.dll) : error LNK2005: "public: static unsigned int __cdecl std::char_traits<char>::length(char const *)" (?length@?$char_traits@D@std@@SAIPBD@Z) already defined in GFTQuantLib.lib(bondfactory.obj)
1>msvcprtd.lib(MSVCP90D.dll) : error LNK2005: "public: class std::basic_ostream<char,struct std::char_traits<char> > & __thiscall std::basic_ostream<char,struct std::char_traits<char> >::flush(void)" (?flush@?$basic_ostream@DU?$char_traits@D@std@@@std@@QAEAAV12@XZ) already defined in GFTQuantLib.lib(date.obj)
1>msvcprtd.lib(MSVCP90D.dll) : error LNK2005: "public: class std::basic_ostream<char,struct std::char_traits<char> > * __thiscall std::basic_ios<char,struct std::char_traits<char> >::tie(void)const " (?tie@?$basic_ios@DU?$char_traits@D@std@@@std@@QBEPAV?$basic_ostream@DU?$char_traits@D@std@@@2@XZ) already defined in GFTQuantLib.lib(date.obj)
1>msvcprtd.lib(MSVCP90D.dll) : error LNK2005: "public: bool __thiscall std::ios_base::good(void)const " (?good@ios_base@std@@QBE_NXZ) already defined in GFTQuantLib.lib(date.obj)
1>msvcprtd.lib(MSVCP90D.dll) : error LNK2005: "public: void __thiscall std::basic_ostream<char,struct std::char_traits<char> >::_Osfx(void)" (?_Osfx@?$basic_ostream@DU?$char_traits@D@std@@@std@@QAEXXZ) already defined in GFTQuantLib.lib(date.obj)
1>msvcprtd.lib(MSVCP90D.dll) : error LNK2005: "public: void __thiscall std::basic_streambuf<char,struct std::char_traits<char> >::_Lock(void)" (?_Lock@?$basic_streambuf@DU?$char_traits@D@std@@@std@@QAEXXZ) already defined in GFTQuantLib.lib(date.obj)
1>msvcprtd.lib(MSVCP90D.dll) : error LNK2005: "public: void __thiscall std::basic_streambuf<char,struct std::char_traits<char> >::_Unlock(void)" (?_Unlock@?$basic_streambuf@DU?$char_traits@D@std@@@std@@QAEXXZ) already defined in GFTQuantLib.lib(date.obj)
1>msvcprtd.lib(MSVCP90D.dll) : error LNK2005: "public: class std::basic_ostream<char,struct std::char_traits<char> > & __thiscall std::basic_ostream<char,struct std::char_traits<char> >::operator<<(double)" (??6?$basic_ostream@DU?$char_traits@D@std@@@std@@QAEAAV01@N@Z) already defined in GFTQuantLib.lib(floatingratebond.obj)
1>msvcprtd.lib(MSVCP90D.dll) : error LNK2005: "public: class std::basic_ostream<char,struct std::char_traits<char> > & __thiscall std::basic_ostream<char,struct std::char_traits<char> >::operator<<(int)" (??6?$basic_ostream@DU?$char_traits@D@std@@@std@@QAEAAV01@H@Z) already defined in GFTQuantLib.lib(date.obj)
1>msvcprtd.lib(MSVCP90D.dll) : error LNK2005: "public: class std::locale::facet * __thiscall std::locale::facet::_Decref(void)" (?_Decref@facet@locale@std@@QAEPAV123@XZ) already defined in GFTQuantLib.lib(date.obj)
1>libcpmtd.lib(ios.obj) : error LNK2005: "private: static void __cdecl std::ios_base::_Ios_base_dtor(class std::ios_base *)" (?_Ios_base_dtor@ios_base@std@@CAXPAV12@@Z) already defined in msvcprtd.lib(MSVCP90D.dll)
1>libcpmtd.lib(ios.obj) : error LNK2005: "public: static void __cdecl std::ios_base::_Addstd(class std::ios_base *)" (?_Addstd@ios_base@std@@SAXPAV12@@Z) already defined in msvcprtd.lib(MSVCP90D.dll)
1>libcpmtd.lib(locale0.obj) : error LNK2005: "void __cdecl _AtModuleExit(void (__cdecl*)(void))" (?_AtModuleExit@@YAXP6AXXZ@Z) already defined in msvcprtd.lib(locale0_implib.obj)
1>libcpmtd.lib(locale0.obj) : error LNK2005: __Fac_tidy already defined in msvcprtd.lib(locale0_implib.obj)
1>libcpmtd.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(locale0_implib.obj)
1>libcpmtd.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(MSVCP90D.dll)
1>libcpmtd.lib(locale0.obj) : error LNK2005: "private: static class std::locale::_Locimp * __cdecl std::locale::_Init(void)" (?_Init@locale@std@@CAPAV_Locimp@12@XZ) already defined in msvcprtd.lib(MSVCP90D.dll)
1>libcpmtd.lib(locale0.obj) : error LNK2005: "public: static void __cdecl std::_Locinfo::_Locinfo_ctor(class std::_Locinfo *,class std::basic_string<char,struct std::char_traits<char>,class std::allocator<char> > const &)" (?_Locinfo_ctor@_Locinfo@std@@SAXPAV12@ABV?$basic_string@DU?$char_traits@D@std@@V?$allocator@D@2@@2@@Z) already defined in msvcprtd.lib(MSVCP90D.dll)
1>libcpmtd.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(MSVCP90D.dll)
1>libcpmtd.lib(xlock.obj) : error LNK2005: "public: __thiscall std::_Lockit::_Lockit(int)" (??0_Lockit@std@@QAE@H@Z) already defined in msvcprtd.lib(MSVCP90D.dll)
1>libcpmtd.lib(xlock.obj) : error LNK2005: "public: __thiscall std::_Lockit::~_Lockit(void)" (??1_Lockit@std@@QAE@XZ) already defined in msvcprtd.lib(MSVCP90D.dll)
1>LIBCMTD.lib(setlocal.obj) : error LNK2005: __configthreadlocale already defined in MSVCRTD.lib(MSVCR90D.dll)
1>LIBCMTD.lib(dbgheap.obj) : error LNK2005: __CrtSetCheckCount already defined in MSVCRTD.lib(MSVCR90D.dll)
1>LIBCMTD.lib(lconv.obj) : error LNK2005: _localeconv already defined in MSVCRTD.lib(MSVCR90D.dll)
1>LIBCMTD.lib(tidtable.obj) : error LNK2005: __encode_pointer already defined in MSVCRTD.lib(MSVCR90D.dll)
1>LIBCMTD.lib(tidtable.obj) : error LNK2005: __decode_pointer already defined in MSVCRTD.lib(MSVCR90D.dll)
1>LIBCMTD.lib(dbghook.obj) : error LNK2005: __crt_debugger_hook already defined in MSVCRTD.lib(MSVCR90D.dll)
1>LIBCMTD.lib(crt0dat.obj) : error LNK2005: _exit already defined in MSVCRTD.lib(MSVCR90D.dll)
1>LIBCMTD.lib(crt0dat.obj) : error LNK2005: __exit already defined in MSVCRTD.lib(MSVCR90D.dll)
1>LIBCMTD.lib(crt0dat.obj) : error LNK2005: __cexit already defined in MSVCRTD.lib(MSVCR90D.dll)
1>LIBCMTD.lib(crt0dat.obj) : error LNK2005: __amsg_exit already defined in MSVCRTD.lib(MSVCR90D.dll)
1>LIBCMTD.lib(crt0dat.obj) : error LNK2005: __initterm_e already defined in MSVCRTD.lib(MSVCR90D.dll)
1>LIBCMTD.lib(mlock.obj) : error LNK2005: __lock already defined in MSVCRTD.lib(MSVCR90D.dll)
1>LIBCMTD.lib(mlock.obj) : error LNK2005: __unlock already defined in MSVCRTD.lib(MSVCR90D.dll)
1>LIBCMTD.lib(winxfltr.obj) : error LNK2005: __XcptFilter already defined in MSVCRTD.lib(MSVCR90D.dll)
1>LIBCMTD.lib(sprintf.obj) : error LNK2005: _sprintf_s already defined in MSVCRTD.lib(MSVCR90D.dll)
1>LIBCMTD.lib(crt0init.obj) : error LNK2005: ___xi_a already defined in MSVCRTD.lib(cinitexe.obj)
1>LIBCMTD.lib(crt0init.obj) : error LNK2005: ___xi_z already defined in MSVCRTD.lib(cinitexe.obj)
1>LIBCMTD.lib(crt0init.obj) : error LNK2005: ___xc_a already defined in MSVCRTD.lib(cinitexe.obj)
1>LIBCMTD.lib(crt0init.obj) : error LNK2005: ___xc_z already defined in MSVCRTD.lib(cinitexe.obj)
1>LIBCMTD.lib(hooks.obj) : error LNK2005: "void __cdecl terminate(void)" (?terminate@@YAXXZ) already defined in MSVCRTD.lib(MSVCR90D.dll)
1>LIBCMTD.lib(invarg.obj) : error LNK2005: __invalid_parameter already defined in MSVCRTD.lib(MSVCR90D.dll)
1>LIBCMTD.lib(invarg.obj) : error LNK2005: __invoke_watson already defined in MSVCRTD.lib(MSVCR90D.dll)
1>LIBCMTD.lib(errmode.obj) : error LNK2005: ___set_app_type already defined in MSVCRTD.lib(MSVCR90D.dll)
1>LIBCMTD.lib(dbgrptw.obj) : error LNK2005: __CrtDbgReportW already defined in MSVCRTD.lib(MSVCR90D.dll)


解决方法:项目属性中,Configuration Properties --> C/C++ --> Code Generation:Runtime Library中的/MDd改为/MTd

继续编译,又产生以下错误:

VSVC编译选项/MDd与/MTd[转]1>msvcrtd.lib(ti_inst.obj) : error LNK2005: "private: __thiscall type_info::type_info(class type_info const &)" (??0type_info@@AAE@ABV0@@Z) already defined in LIBCMTD.lib(typinfo.obj)
VSVC编译选项/MDd与/MTd[转] 1>msvcrtd.lib(ti_inst.obj) : error LNK2005: "private: class type_info & __thiscall type_info::operator=(class type_info const &)" (??4type_info@@AAEAAV0@ABV0@@Z) already defined in LIBCMTD.lib(typinfo.obj)


原因:既用了MSVCRTD.lib又用了LIBCMTD.lib,而现在的情况是需要LIBCMTD.lib,所以需要去掉MSVCRTD.lib
解决方法:在项目属性中,Configuration Properties --> Linker --> Input:Ignore Specific Library里填入MSVCRTD.lib。
编译,成功。

 

在各个版本的编译器中,我们可以通过配置选项来设置程序使用的C和C++运行时库的类型。如下图(其他版本编译器大同小异):

 

 

MT选项:链接LIB版的C和C++运行库。在链接时就会在将C和C++运行时库集成到程序中成为程序中的代码,程序体积会变大。 
MTd选项:LIB的调试版。 
MD选项:使用DLL版的C和C++运行库,这样在程序运行时会动态的加载对应的DLL,程序体积会减小,缺点是在系统没有对应DLL时程序无法运行。 
MDd选项:表示使用DLL的调试版。

关于C和C++运行库的概念
  为了提高C语言的开发效率,C标准定义了一系列常用的函数,称为C库函数。C标准仅仅定义了函数原型,并没有提供实现。因此这个任务留给了各个支持C语言标准的编译器。每个编译器通常实现了标准C的超集,称为C运行时库(C Run Time Library),简称CRT。对于VC++编译器来说,它提供的CRT库支持C标准定义的标准C函数,同时也有一些专门针对Windows系统特别设计的函数 
  与C语言类似,C++也定义了自己的标准,同时提供相关支持库,称为C++运行时库或C++标准库。由于C++对C的兼容性,C++标准库包括了C标准库,除此之外还包括了IO流和标准模板库STL。

VC++在何处实现C和C++运行库
  VC++完美的支持C和C++标准,因此也就按照C和C++标准定义的函数原型实现了上述运行时库。为了方便有不同需求的客户使用,VC++分别实现了动态链接库DLL版本和静态链接库LIB版本。同时为了支持程序调试且不影响程序的性能,又分别提供了对应的调试版本。调试版本的名称在Release版本名称后添加了字母d。

对于C运行时库CRT,VC6.0、VC2005、VC2008和VC2010均提供了DLL版本和LIB版本。 
上述各个编译器提供的LIB版的CRT库,均实现在libcmt.lib。对应的调试版名称为libcmtd.lib。

而DLL版本名称根据编译器不同而不同,我们可以从名称上加以分辨。 
  VC6.使用的CRT库的DLL版本在MSVCRT.DLL中实现, 对应调试版本为MSVCRTD.LIB。 
  VC2005使用的CRT库的DLL版本在MSVCR80.DLL中实现,对应调试版本为MSVCR80.DLL。 
  VC2008使用的CRT库的DLL版本在MSVCR90.DLL中实现,对应调试版本为MSVCR90D.DLL。 
  VC2010使用的CRT库的DLL版本在MSVCR100.DLL中实现,对应调试版本为MSVCR100D.DLL。 
  VC2013使用的CRT库的DLL版本在MSVCR120.DLL中实现,对应调试版本为MSVCR120D.DLL。

 

 

对于C++标准库中的IO流和STL,VC6.0、VC2005、VC2008和VC2010也提供了DLL版本和LIB版本。 
  LIB版均实现在libcpmt.lib中,对应的调试版本为libcpmtd.lib。 
不同版本的编译器实现的DLL也不相同。 
  VC6.使用的C++类库的 DLL版本在MSVCP60.DLL中实现, 对应调试版本为MSVCP60D.LIB。 
  VC2005使用的C++类库的DLL版本在MSVCP80.DLL中实现,对应调试版本为MSVCP80.DLL。 
  VC2008使用的C++类库的 DLL版本在MSVCP90.DLL中实现,对应调试版本为MSVCP90D.DLL。 
  VC2010使用的C++类库的DLL版本在MSVCP100.DLL中实现,对应调试版本为MSVCP100D.DLL。

 我们编译的exe要在没有vs环境的机器上正常运行需要,如果编译选择是动态链接需要带上对应的运行时库

DeBug:

          

Release:

             

 

动态版(DLL)和静态版(LIB)C和C++运行库的优缺点
  因为静态版必须把C和C++运行库复制到目标程序中(.exe),所以产生的可执行文件会比较大。同时对于使用多个模块的大型软件来说,如果每个模块均选择静态链接C或C++运行库,在程序运行时就会存在多个运行库。在链接时也会出现重复定义的问题,如图所示。

  使用DLL版的C和C++运行库,程序在运行时动态的加载对应的DLL。程序体积变小,但一个很大的问题就是一旦找不到对应DLL,程序将无法运行(比如所要移植的电脑没有安装VC++)。假设使用VC6.0并选择使用MD选项构建,那么当用户使用VC2005来使用这个DLL时很可能出现找不到MSVCRT.DLL或MSVCP60.DLL的情况。

 

posted @ 2016-06-23 18:34  车臣  阅读(961)  评论(0编辑  收藏  举报