简短回答:
所以,我的理解是,如果您与第三方链接
库,您应该使用用于构建的相同 CRT 版本
图书馆。构建库的人应该指定什么 CRT 选项
在构建中使用了。
这是最不容易出错的选项。可以混合运行时,但如果这样做,您可能会遇到意想不到的错误。
有没有一种方法可以通过查看来确定使用的是哪个 CRT 版本
在 .lib 文件中?
我不知道.lib
其本身,但如果第三方代码有 DLL 或 EXE,您可以使用 Windows 查看它依赖于哪个 CRT DLL依赖步行者 http://www.dependencywalker.com/ tool.
如果它是静态库,并且您的代码的 CRT 选择不匹配,则您在构建时会看到警告。
更重要的是,如果您
没有与任何第三方库链接?你什么时候会考虑
更改默认值?
对于最简单的部署,静态链接是最好的;您可以单独发送可执行文件,它就会运行。对于具有多个 EXE 和 DLL 的大型项目,如果静态链接,代码大小将会更大。如果同一进程中有多个模块(EXE 加上 1 个或多个您自己的 DLL),最好共享相同的 CRT 代码。
更多细节(基于我之前写的博客文章):
库变体
您可以根据 C/C++ 运行时库的四种变体构建代码:
- 多线程调试DLL
- 多线程DLL
- 多线程调试
- 多线程
您可以通过右键单击 Visual Studio 中的项目并选择“属性”,然后单击代码生成下的选项C/C++在弹出的对话框中,然后转到运行时库财产。
请记住,此设置是针对每个配置的,因为您需要选择一个Debug运行时库Debug配置,以及Release运行时库Release配置。
有什么不同?
The DLL运行时库选项意味着您可以动态链接到 C/C++ 运行时,并且为了让您的程序运行,DLL需要在你的程序可以找到它的地方(稍后会详细介绍)。
未提及 DLL 的选项(多线程调试 and 多线程发布)使您的程序与运行时静态链接。这意味着您不需要外部 DLL 来运行程序,但是您的程序会因为额外的代码而变得更大,并且还有其他原因您可能不想选择它。
默认情况下,当您在 Visual Studio 中创建新项目时,它将使用DLL运行。
运行时名称中的多线程是过去同时存在非线程安全和多线程 C/C++ 运行时的遗留问题。你将永远使用多线程即使您自己的应用程序是单线程的,也可以使用现代 Visual Studio 运行时。
部署 DLL 运行时
如果您要链接 DLL 运行时,那么您必须考虑在发布程序(测试和客户)时如何部署它们。
如果你送货Debug为您的测试团队构建,请确保您也提供 DLL 运行时的调试变体。
另外,不要忘记获得正确的架构(例如x86 vs x64).
可再发行安装程序
Microsoft 提供了可再发行的软件包来安装Release(但不是Debug) DLL。通过搜索类似的内容可以很容易地找到这些Visual C++ 可再发行版 2013(将 Visual Studio 版本替换为您需要的版本)。您也可以直接前往最新支持的 Visual C++ 下载 http://support.microsoft.com/kb/2019667在微软的网站上。
这些可再发行包是可执行文件,您可以从程序的安装程序中调用它们(或者您可以手动运行它们以设置测试环境)。请注意,x86 和 x64 有单独的可再发行版本。
合并模块
如果您正在构建 MSI 安装程序,您可以合并合并模块 https://msdn.microsoft.com/en-us/library/aa369820%28v=vs.85%29.aspx对于您在安装程序包中使用的 C/C++ 运行时。这些合并模块通常位于C:\Program Files (x86)\Common Files\Merge Modules
。例如,Visual Studio 2013 的 x86 C/C++ 运行时合并模块称为Microsoft_VC120_CRT_x86.msm
.
请注意,这些合并模块名称中的版本号不是基于年份的产品版本,而是内部版本号。维基百科上的这个表 http://en.wikipedia.org/wiki/Microsoft_Visual_Studio#History显示版本号之间的映射以避免混淆。
与上面的独立可执行可再发行安装程序不同,合并模块也有调试变体。
某些版本的 Visual Studio 支持视觉工作室安装程序项目类型(下设置和部署类别在其他项目类型),如果您将程序项目的输出包含在这些安装程序之一中,则运行时的合并模块将自动包含在内。您还可以使用此技巧来获取将安装Debug用于内部测试目的的运行时(任何虚拟 C/C++ 项目都可以,它不必实际安装您的程序)。
从 Redist 文件夹复制
您还可以将 DLL 从 Visual C++ 安装中的 redist 文件夹复制到程序安装位置。例如,对于 Visual Studio 2013,您将在类似位置找到 x64 C/C++ 运行时库C:\Program Files (x86)\Microsoft Visual Studio 12.0\VC\redist\x64\Microsoft.VC120.CRT\
.
调试变体可以在类似的地方找到C:\Program Files (x86)\Microsoft Visual Studio 12.0\VC\redist\Debug_NonRedist
.
(根据您的 Visual Studio 版本和安装位置调整路径)。
混合 C/C++ 运行时
在理想情况下,您将使用相同的 C/C++ 运行时库变体(Debug vs Release, DLL vs 静态链接),并且全部来自同一版本的 Visual Studio,对于链接到程序中的所有库。
如果您混合运行时,您可能会遇到链接器错误,您的程序可能根本无法运行,或者更糟糕的是,它可能看起来可以工作,但仅在某些情况下崩溃或给出错误的结果。
忽略默认库
一个常见的情况是您只有Release某些第三方库的版本,但您仍然希望能够构建Debug使用此库的您自己的代码的变体。另一种情况是,您有一个使用静态 C/C++ 运行时的库,并且您想要DLL程序中的版本,或者相反。
如果第三方库是 C 代码,那么您可能能够摆脱这一点并让它实际工作,使用/NODEFAULTLIB链接器选项 https://msdn.microsoft.com/en-us/library/3tz4da4a.aspx.
如果库是 C++ 代码,您可能会运气不好,因为生成的代码中有太多与特定运行时中的符号相关联。
这些是不同的库名称:
-
LIBCMT库:静态链接的发布运行时(也称为多线程)
-
LIBCMTD库:静态链接的调试运行时(也称为多线程调试)
-
MSVCRT库:动态链接的发布运行时(也称为多线程深度学习L)
-
MSVCRTD库:动态链接的调试运行时(也称为多线程调试DLL)
请记住,您想要忽略的运行时库是第三者代码正在使用,即它将与您自己的程序正在使用的库不同。如果您查看构建输出,系统将提示您选择正确的输出,例如:
LINK : warning LNK4098: defaultlib 'LIBCMTD' conflicts with use of other libs; use /NODEFAULTLIB:library
您可以通过右键单击项目并选择来指定要忽略的库特性,单击Input条目下Linker并将运行时库名称添加到条目中。
跨越模块边界
您还可能以更微妙的方式跨模块边界(例如在 EXE 和它加载的 DLL 之间)遇到 C/C++ 运行时不匹配问题。
例如,C 库中的数据结构可能由不同的运行时定义不同。我见过这会导致使用 DLL 的程序崩溃,而该 DLL 使用了FILE*
在它的 API 中。文件是使用一个 C 运行时在一个模块中打开的,并由具有不同、不兼容实现的另一个模块进行交互。更安全的选择包括传递 Windows APIHANDLE
诸如此类的对象,或者以与运行时无关的方式包装文件交互。
不同的运行时还使用自己的内存堆进行分配。如果一个对象在一个堆上的一个模块中分配,但在另一个模块中释放,则如果 C/C++ 运行时不匹配,则可能会发生崩溃。当然,这仅适用于使用 C 或 C++ 运行时的分配,例如malloc
or new
。例如,如果到处都使用默认的 Windows 进程堆,则一切都很好。
请注意,如果模块静态链接到 C/C++ 运行时,即使它们链接的运行时是相同的变体,它们也会遇到此问题,因为仍然存在两个不同的运行时,它们拥有自己的内存堆。因此,在这种情况下您将需要使用 DLL C/C++ 运行时。
如果运行时实现的功能(例如异常或带有 vtable 的类)跨越模块边界,那么在每个模块中使用(相同版本的)DLL 运行时也是明智的,尽管某些不匹配的组合在实践中可能会起作用。