1 编译器选项

2 C 运行时 (CRT) 和 C++ 标准库 (STL).lib 文件

本节翻译自: https://learn.microsoft.com/en-us/cpp/c-runtime-library/crt-library-features?view=msvc-170&viewFallbackFrom=vs-2019

Note

微软的 C++ 标准库实现通常被称为 STL 或标准模板库。虽然 C++ 标准库是 ISO 14882 定义的库的正式名称,但由于“STL”和“标准模板库”在搜索引擎中的使用较为广泛,我们偶尔也会使用这些名称,以便于查找我们的文档。

从历史角度来看,“STL”最初指的是 Alexander Stepanov 编写的标准模板库 (STL)。该库的部分内容已在 C++ 标准库中标准化。该标准库还包含 ISO C 运行时库、Boost 库的部分内容以及其他功能。有时,“STL”也指由 Stepanov 的 STL 改编而来的 C++ 标准库中的容器和算法部分。在本文档中,标准模板库 (STL) 指的是整个 C++ 标准库。

2.1 C 运行时 .lib 文件

ISO C 标准库是 C++ 标准库的一部分。实现 CRT 的 Visual C++ 库支持本机代码开发,以及混合本机代码和托管代码。所有版本的 CRT 都支持多线程开发。大多数库都支持静态链接(将库直接链接到代码中)或动态链接(允许代码使用通用 DLL 文件)。

在 Visual Studio 2015 中,CRT 被重构为新的二进制文件。通用 CRT (UCRT) 包含标准 C99 CRT 库导出的函数和全局变量。UCRT 现在是 Windows 组件,并作为 Windows 10 及更高版本的一部分提供。UCRT 的静态库、DLL 导入库和头文件现在可以在 Windows SDK 中找到。安装 Visual C++ 时,Visual Studio 安装程序会安装使用 UCRT 所需的 Windows SDK 子集。您可以在 Visual Studio 2015 及更高版本支持的任何 Windows 版本上使用 UCRT。您可以使用 vcredist 将其重新分发给 Windows 10 或更高版本以外的受支持 Windows 版本。有关更多信息,请参阅 重新分发 Visual C++ 文件

下表列出了实现 UCRT 的库。

图书馆关联 DLL特征选项预处理器指令
libucrt.lib没有任何将 UCRT 静态链接到您的代码中。/MT_MT
libucrtd.lib没有任何静态链接的 UCRT 调试版本。不可再分发用于。/MTd_DEBUG_MT
ucrt.libucrtbase.dllUCRT 的 DLL 导入库。/MD_MT_DLL
ucrtd.libucrtbased.dllUCRT 调试版本的 DLL 导入库。不可再分发。/MDd_DEBUG_MT_DLL

vcruntime 库包含 Visual C++ CRT 实现特定的代码:异常处理和调试支持、运行时检查和类型信息、实现细节以及某些扩展库函数。vcruntime 库版本需要与你使用的编译器版本匹配。

下表列出了实现 vcruntime 库的库。

图书馆关联 DLL特征选项预处理器指令
libvcruntime.lib没有任何静态链接到您的代码。/MT_MT
libvcruntimed.lib没有任何使用静态链接的调试版本。不可重新分发。/MTd_MT_DEBUG
vcruntime.libvcruntime<version>.dllvcruntime 的 DLL 导入库。/MD_MT_DLL
vcruntimed.libvcruntime<version>d.dll用于调试 vcruntime 的 DLL 导入库。不可再分发。/MDd_DEBUG_MT_DLL

Note

重构 UCRT 时,并发运行时函数被移至 concrt140.dll,后者已添加到 C++ 可再发行组件包中。此 DLL 是 C++ 并行容器和算法(例如 concurrency::parallel_for )所必需的。此外,由于 Windows XP 没有条件变量,C++ 标准库需要 Windows XP 上的此 DLL 来支持同步基元。

初始化 CRT 的代码位于多个库之一中,具体取决于 CRT 库是静态链接、动态链接,还是本机代码、托管代码或混合代码。此代码处理 CRT 启动、内部每线程数据初始化和终止。它特定于所使用的编译器版本。此库始终是静态链接的,即使使用动态链接的 UCRT 也是如此。

下表列出了实现 CRT 初始化和终止的库。

图书馆特征选项预处理器指令
libcmt.lib将本机 CRT 启动静态链接到您的代码中。/MT_MT
libcmtd.lib静态链接本机 CRT 启动的调试版本。不可再分发。/MTd_DEBUG_MT
msvcrt.lib用于本机 CRT 启动的静态库,可与 DLL UCRT 和 vcruntime 一起使用。/MD_MT_DLL
msvcrtd.lib本机 CRT 启动的调试版本的静态库,可与 DLL UCRT 和 vcruntime 一起使用。不可再分发使用。/MDd_DEBUG_MT_DLL
msvcmrt.lib用于本机和托管 CRT 启动混合的静态库,可与 DLL UCRT 和 vcruntime 一起使用。/clr
msvcmrtd.lib用于本机和托管 CRT 启动混合的调试版本的静态库,可与 DLL UCRT 和 vcruntime 一起使用。不可再分发。/clr
msvcurt.lib纯托管 CRT 的静态库已废弃。/clr:pure
msvcurtd.lib纯托管 CRT 调试版本的已废弃使用静态库。不可重新分配。/clr:pure

如果您从命令行链接程序时没有使用指定 C 运行时库的编译器选项,则链接器将使用静态链接的 CRT 库:libcmt.liblibvcruntime.liblibucrt.lib

使用静态链接的 CRT 意味着 C 运行时库保存的任何状态信息都将是该 CRT 实例的本地信息。例如,如果您在使用静态链接的 CRT 时使用 strtok ,则 strtok 解析器的位置与链接到另一个静态 CRT 实例的同一进程(但在不同的 DLL 或 EXE 中)中的代码中使用 strtok 的状态无关。相反,动态链接的 CRT 共享动态链接到 CRT 的进程内所有代码的状态。如果您使用这些函数的新的更安全的版本,则不存在此问题;例如,strtok_s 不存在此问题。

由于通过链接到静态 CRT 构建的 DLL 具有其自己的 CRT 状态,因此,除非了解并期望其后果,否则我们不建议你静态链接到 DLL 中的 CRT。例如,如果你调用 _set_se_translator 一个可执行文件,而该可执行文件加载了链接到其自己的静态 CRT 的 DLL,则转换器将无法捕获 DLL 中的代码生成的任何硬件异常,但可以捕获主可执行文件中的代码生成的硬件异常。

如果您使用 /clr 编译器开关,您的代码将与静态库 msvcmrt.lib 链接。静态库在托管代码和本机 CRT 之间提供代理。您不能将静态链接的 CRT(/MT/MTd 选项)与 /clr 一起使用。请改用动态链接库(/MD/MDd)。纯托管 CRT 库在 Visual Studio 2015 中已弃用,并且在 Visual Studio 2017 中不受支持。

有关使用 CRT 的更多信息 /clr,请参阅 混合(本机和托管)程序集

要构建应用程序的调试版本,_DEBUG 必须定义该标志,并且必须将应用程序链接到其中一个库的调试版本。有关使用库文件的调试版本的更多信息,请参阅 CRT 调试技术

此版本的 CRT 不完全符合 C99 标准。在 Visual Studio 2019 16.8 版之前的版本中,<tgmath.h> 不支持标头。所有版本均不支持 CX_LIMITED_RANGEFP_CONTRACT 编译指示宏。某些元素(例如标准 IO 函数中参数说明符的含义)默认使用旧式解释。您可以使用**/Zc**编译器一致性选项并指定链接器选项来控制库一致性的某些方面。

2.2 C++ 标准库 (STL).lib 文件

C++ 标准库特征选项预处理器指令
libcpmt.lib多线程、静态链接/MT_MT
msvcprt.lib多线程、动态链接(msvcp<version>.dll 的导入库)/MD_MT_DLL
libcpmtd.lib多线程、静态链接/MTd_DEBUG_MT
msvcprtd.lib多线程、动态链接(msvcp<version>d.dll 的导入库)/MDd_DEBUG_MT_DLL

构建项目的发布版本时,会默认链接一个基本 C 运行时库(libcmt.libmsvcmrt.libmsvcrt.lib),具体取决于你选择的编译器选项(多线程、DLL、 /clr)。如果你在代码中包含一个 C++ 标准库头文件,Visual C++ 会在编译时自动链接一个 C++ 标准库。例如:

#include <ios>

为了实现二进制兼容性,一个导入库可以指定多个 DLL 文件。版本更新可能会引入 点库 ,即引入新库功能的独立 DLL。例如,Visual Studio 2017 15.6 版引入了 msvcp140_1.dll 更多标准库功能,且不会破坏所支持的应用程序二进制接口 (ABI) msvcp140.dll。Visual msvcprt.libStudio 2017 15.6 版工具集中包含的导入库支持这两个 DLL,此版本的 vcredist 会安装这两个 DLL。点库一旦发布便具有固定的 ABI,并且永远不会依赖于更高版本的点库。

2.3 ⭐ 如果应用程序使用多个 CRT 版本,会出现什么问题?

每个可执行映像(EXE 或 DLL)都可以拥有自己的静态链接 CRT,也可以动态链接到 CRT。特定映像静态包含或动态加载的 CRT 版本取决于构建该映像所使用的工具和库的版本。单个进程可以加载多个 EXE 和 DLL 映像,每个映像都有自己的 CRT。每个 CRT 可能使用不同的分配器,具有不同的内部结构布局,并且使用不同的存储安排。这意味着分配的内存、CRT 资源或跨 DLL 边界传递的类可能会导致内存管理、内部静态使用或布局解释方面的问题。例如,如果一个类在一个 DLL 中分配,但传递给另一个 DLL 并被另一个 DLL 删除,那么应该使用哪个 CRT 释放器?由此造成的错误可能很小,也可能立即致命,因此不建议直接传输此类资源。

您可以使用应用程序二进制接口 (ABI) 技术来避免许多此类问题,因为它们的设计目标是稳定且可版本控制。设计您的 DLL 导出接口以按值传递信息,或处理由调用方传入的内存,而不是在本地分配并返回给调用方的内存。使用封送处理技术在可执行映像之间复制结构化数据。在本地封装资源,并且仅允许通过向客户端公开的句柄或函数进行操作。

如果进程中的所有映像都使用相同的动态加载版本的 CRT,也可以避免其中一些问题。为了确保所有组件都使用相同的 DLL 版本的 CRT,请使用选项 /MD 构建它们,并使用相同的编译器工具集和属性设置。

如果您的程序跨 DLL 边界传递某些 CRT 资源,请务必小心。即使使用相同版本的 CRT,文件句柄、区域设置和环境变量等资源也可能导致问题。有关相关问题及其解决方法的更多信息,请参阅 跨 DLL 边界传递 CRT 对象时可能出现的错误

3 FAQ

3.1 msvc 中有的库是不可再分发的,是什么意思

Faq

在 MSVC(Microsoft Visual C++)中,“有的库是不可再分发的”的意思是:

这些库文件只能在开发/编译阶段使用,不能被你打包、复制或随你的应用程序一起分发给其他用户或部署到其他设备上。

一、什么叫“再分发”?

再分发(redistribution)是指你在发布自己的程序时,把它依赖的运行时库(DLL 或 LIB 文件)一并打包给用户的行为。

常见合法的再分发形式:

  • 安装包中附带 DLL(如 vcruntime140.dll
  • 发布静态链接版本(如使用 /MT 编译选项)
  • 引导用户安装 Visual C++ Redistributable(官方安装器)

二、哪些库是不可再分发的?

MSVC 中有些库属于仅供开发使用的库,不允许你复制或打包进自己的程序中,比如:

类型举例是否可再分发说明
调试版 CRT 库MSVCRTD.lib, ucrtd.dll(debug)只能用于调试和开发,不能用于生产环境或发布给用户
一些内部工具库vcpkg 临时构建的 DLL、MS internal tools仅供编译/测试阶段使用
MSVC 编译工具本身cl.exe, link.exe, c1xx.dll属于工具链组件,受 EULA 限制

✅ 可再分发的库一般包括:

  • Release 模式下的运行库 DLL,例如:

    • vcruntime140.dll
    • msvcp140.dll
    • concrt140.dll
  • 这些库来自微软的官方 VC++ Redistributable 安装包

三、如何判断某个库是否可以再分发?

  1. 查阅 Microsoft 官方 Redistributable List

  2. 通过库路径判断

    • 如果库文件在如下路径中,一般是“不可再分发”:

      C:\Program Files (x86)\Microsoft Visual Studio\2022\BuildTools\VC\Tools\MSVC\<version>\debug\...
      
  3. 查看文件是否带有 _d 后缀

    • msvcp140d.dll → 调试版,不可再分发
    • 没有 d → 正式版,可再分发
  4. 查阅 EULA(许可协议)

四、违反再分发限制的后果

  • 违反微软许可协议(Microsoft Software License Terms)
  • 法律风险(尤其在商业软件中)
  • 程序在其他机器上无法运行(因为缺失合法的运行库)

五、安全做法建议

目标推荐做法
打包运行库使用微软的 VC++ Redistributable
避免发布调试库构建发布版(Release),并避免链接 _d 版本的 DLL
静态链接运行库使用 /MT/MTd(需注意 LGPL 等开源库兼容性)
使用 vcpkg 等工具只发布 Release 构建产物,排除 vcpkg 的 debug 库

4 更多参考