Visual studio 2015 运行-time dependencies 或者如何摆脱 Universal CRT?
Visual studio 2015 run-time dependencies or how to get rid of Universal CRT?
使用 visual studio 2015 编译了几个 .dll,并尝试在一些较旧的 windows 7 / 64 位上部署。还尝试猜测应用程序启动和复制需要哪些 dll MSVCP140.DLL & VCRUNTIME140.DLL - 但应用程序无法加载 vs2015 dll。开始分析出了什么问题——依赖 walker 显示了来自以下 dll 的依赖:
API-MS-WIN-CRT-MATH-L1-1-0.DLL
API-MS-WIN-CRT-HEAP-L1-1-0.DLL
API-MS-WIN-CRT-CONVERT-L1-1-0.DLL
API-MS-WIN-CRT-STRING-L1-1-0.DLL
API-MS-WIN-CRT-STDIO-L1-1-0.DLL
API-MS-WIN-CRT-RUNTIME-L1-1-0.DLL
API-MS-WIN-CRT-FILESYSTEM-L1-1-0.DLL
API-MS-WIN-CRT-TIME-L1-1-0.DLL
这尤其令人惊讶,因为据我所知,CRT 负责启动 dll/exe,它不提供任何更高级别的服务。
好吧,我试着弄清楚如何摆脱它们或至少将它们最小化。
找到一篇文章:
https://blogs.msdn.microsoft.com/vcblog/2015/03/03/introducing-the-universal-crt/
它提到了发布静态库 - 所以我认为我可以 link 对抗它们并摆脱 *L1-1-0.DLL* 依赖地狱,但无论我尝试了什么- 我没有成功。我尝试 link 反对 libvcruntime.lib、libucrt.lib、libcmt.lib,尝试使用 linker 选项“/nodefaultlib:vcruntime.lib”禁用,甚至尝试添加包含目录 $(UniversalCRT_IncludePath),并且还覆盖了一些定义,因为我试图猜测它们有效 - none 我的尝试有所帮助。
作为中间解决方案,我回退到使用 Visual studio 2013,其中 CRT dll 只有两个:msvcp120.dll、msvcr120.dll.
当然,您可能会建议安装 Visual studio 2015 运行 次,但我们的要求之一是支持独立的可执行文件——无需任何安装即可运行——因此无需额外安装现在的问题。
除了等待 Visual studio 2017 年到来,你还能给我推荐什么吗?
(2016 年 10 月 11 日更新)。
可以通过 link 静态化它来摆脱通用 CRT,我稍后会谈到它,但让我们来看看
看看您是否继续这样使用通用 CRT。
根据文章 https://blogs.msdn.microsoft.com/vcblog/2015/03/03/introducing-the-universal-crt/ -
可以使用以下文件夹中的通用 crt dll 可分发文件启动您的应用程序:
C:\Program Files (x86)\Windows Kits\Redist\ucrt
列表中共有41个文件,总大小为1.8Mb。 (64 位平台示例)
当然这还不够,您还需要来自以下文件夹的 vcruntime140.dll & msvcp140.dll:
C:\Program Files (x86)\Microsoft Visual Studio 14.0\VC\redist\x64\Microsoft.VC140.CRT
因此,除了您的应用程序之外,您还将交付总共 43 个额外的 dll。
也可以在您的应用程序中静态编译 ucrt 库,之后您将不需要 43 个 dll -
但是 static link 是否会在 linking 之后 - 取决于你的应用程序 - 有多少 dll 和哪些 api 正在使用。
通常在 ucrt linked 到两个不同的 dll 之后,它们不一定彼此共享相同的全局变量——这可能会导致错误。
您需要 link 对抗 vcruntime.lib / msvcrt.lib,但这还不够 - 还有额外的 _VCRTIMP=
和 _ACRTIMP=
定义需要禁用从 ucrt 中提取函数的功能。
如果您使用的是 premake5,您可以像这样配置您的项目:
defines { "_VCRTIMP="}
linkoptions { "/nodefaultlib:vcruntime.lib" }
links { "libvcruntime.lib" }
其次是:
defines { "_ACRTIMP="}
linkoptions { "/nodefaultlib:msvcrt.lib" }
links { "libcmt.lib" }
Microsoft 未记录定义 - 因此将来可能会更改。
除了您自己的项目,您还需要重新编译您项目中使用的所有静态库。
至于 boost 库——我也成功编译了 boost,使用 b2.exe boostrapper
boost>call b2 threading=multi toolset=msvc-14.0 address-model=64 --stagedir=release_64bit --build-dir=intermediate_64but release link=static,shared --with-atomic --with-thread --with-date_time --with-filesystem define=_VCRTIMP= define=_ACRTIMP=
解决 linking 问题时 - 请注意未解析的 __imp*
函数名称来自 dllimport
关键字用法 -
如果你 link 反对 libvcruntime.lib,你不应该有任何 __imp*
引用。
我能够通过设置
C/C++ > Code Generation > Runtime Library
编译器选项
- 对于调试:从
/MDd
到 /MTd
- 待发布:从
/MD
到 /MT
这删除了所有 API-MS-WIN-CRT-*
和运行时 dll 引用并导致所有 CRT 代码静态链接。
有关新的 VS2015 通用 CRT(动态和静态)的详细信息,请参见此处:
https://msdn.microsoft.com/en-us/library/abx4dbyh.aspx
我也在与静态 link 解决方案作斗争,该解决方案具有多个 components/project 库依赖项,从 MSVCRT、UCRT 和内核的各个部分导入函数。希望生成的 EXE 可以复制到需要的地方(它不是可以证明完整 MSI 安装合理的产品)。
在几乎放弃之后,我发现最好的解决方案是遵循隐藏在 Universal C Runtime announcement 中的指南,特别是:
We strongly recommend against static linking of the Visual C++
libraries, for both performance and serviceability reasons
只需删除您尝试过的所有 "special" linker 选项,返回 /MT|/MD(多线程 CRT DLL 发布|调试)运行时间库选择,它无处不在,例如较新的 Windows 10 个工作站、2012 R2 服务器和 Windows 7)。正如微软告诉我们的那样 install/redistribute MSVCRT (VC_Redist*.exe) and KB2999226 (UCRT via Windows Update),因为正如他们所说:
The Universal CRT is a component of the Windows operating system. It
is included as a part of Windows 10, starting with the January
Technical Preview, and it is available for older versions of the
operating system via Windows Update.
因此,从逻辑上讲,我们的 C++ 解决方案为客户添加的唯一额外部署依赖项是 MSVCRT,因为 UCRT 应该已经存在于 up-to-date/well 维护的机器上。当然,这增加了一些不确定性;你不能只在任何机器上复制 EXE 和 运行,无论好坏。
如果您生成像 MSI 这样的像样的部署包,那么当您拥有像 WIX 这样的工具时,它很容易包含。另外需要注意的是,由于最近的 SDK 可以在本地包含 40 多个 DLL,但这不符合安全更新原则,所以我不会这样做。
这确实是唯一受支持的方法,see another example here。本文还建议我们 link 反对 "mincore_downlevel.lib" 这是一个重要的提示,对于您是否遇到这些 "api-ms-win*" 丢失的 DLL 错误至关重要。例如:
- 项目 SDK 版本设置为 10,link 且 mincore.lib = 仅在 Windows 10 上运行,而不是 8.1/2012 R2 或 Windows 7/2008 R2服务器。
- 项目 SDK 版本设置为 8.1,link,mincore.lib = 在 Windows 10 和 8.1/2012 R2 服务器上运行,但不在 Windows 7/2008 R2 服务器。
- 项目 SDK 版本设置为 10,link 和 mincore_downlevel.lib = 全部运行!
总结:
- 不要 link 静态,在项目设置中保留默认 DLL C 运行 次选择。
- 您不需要旧的 SDK,可以使用最新的 Windows 10 SDK 进行开发,但是您必须 link 使用 "mincore_downlevel.lib" 而不是 "mincore.lib" 如果需要支持旧的 Windows 版本。
- 为了便于使用,将此添加到您的 targetver.h 或 stdafx.h 中,这也记录了您的选择(删除另一行):
// Libraries
#pragma comment(lib, "mincore.lib") // Lowest OS support is same as SDK
#pragma comment(lib, "mincore_downlevel.lib") // Support OS older than SDK
我费了很大劲才找到 运行 2015 年 Visual Studio 构建的应用程序所需的 运行 时间 DLL。
在这里我发现了以下允许 VS-2015 构建的应用程序 运行。
- 从 https://www.microsoft.com/en-us/download/details.aspx?id=52685
下载可再发行组件
- 放置 msvcp140d.dll、vccorlib140d.dll、vcruntime140d.dll 和 ucrtbased.dll。
注意:根据您的系统处理器架构(x86、x64..)放置 dll 版本。
设置:配置属性 - 高级 - MFC 的使用 - "Use MFC in a Static Library" 对我有用(使用控制台应用程序 - 而不是 MFC/ATL 应用程序本身)。
如果您不想用自己的运行时替换运行时,那么是否
并不重要
- 您有运行时键入 enabled/disabled
- 您有 C++ 异常 enabled/disabled
- 您是否将运行时库设置为多线程 DLL(将其设置为非 DLL 仍在将其构建到您的二进制文件中)
您唯一需要确保的是您不使用它的任何功能,并且Visual Studio自动不会link使用它. IE。没有断言,没有调用 string.h 或 stdio.h 中的任何内容,什么都没有。编译器可以用自己的内在函数替换的任何东西都可以,编译器检查也是如此 static_assert.
使用 visual studio 2015 编译了几个 .dll,并尝试在一些较旧的 windows 7 / 64 位上部署。还尝试猜测应用程序启动和复制需要哪些 dll MSVCP140.DLL & VCRUNTIME140.DLL - 但应用程序无法加载 vs2015 dll。开始分析出了什么问题——依赖 walker 显示了来自以下 dll 的依赖:
API-MS-WIN-CRT-MATH-L1-1-0.DLL
API-MS-WIN-CRT-HEAP-L1-1-0.DLL
API-MS-WIN-CRT-CONVERT-L1-1-0.DLL
API-MS-WIN-CRT-STRING-L1-1-0.DLL
API-MS-WIN-CRT-STDIO-L1-1-0.DLL
API-MS-WIN-CRT-RUNTIME-L1-1-0.DLL
API-MS-WIN-CRT-FILESYSTEM-L1-1-0.DLL
API-MS-WIN-CRT-TIME-L1-1-0.DLL
这尤其令人惊讶,因为据我所知,CRT 负责启动 dll/exe,它不提供任何更高级别的服务。
好吧,我试着弄清楚如何摆脱它们或至少将它们最小化。
找到一篇文章: https://blogs.msdn.microsoft.com/vcblog/2015/03/03/introducing-the-universal-crt/
它提到了发布静态库 - 所以我认为我可以 link 对抗它们并摆脱 *L1-1-0.DLL* 依赖地狱,但无论我尝试了什么- 我没有成功。我尝试 link 反对 libvcruntime.lib、libucrt.lib、libcmt.lib,尝试使用 linker 选项“/nodefaultlib:vcruntime.lib”禁用,甚至尝试添加包含目录 $(UniversalCRT_IncludePath),并且还覆盖了一些定义,因为我试图猜测它们有效 - none 我的尝试有所帮助。
作为中间解决方案,我回退到使用 Visual studio 2013,其中 CRT dll 只有两个:msvcp120.dll、msvcr120.dll.
当然,您可能会建议安装 Visual studio 2015 运行 次,但我们的要求之一是支持独立的可执行文件——无需任何安装即可运行——因此无需额外安装现在的问题。
除了等待 Visual studio 2017 年到来,你还能给我推荐什么吗?
(2016 年 10 月 11 日更新)。
可以通过 link 静态化它来摆脱通用 CRT,我稍后会谈到它,但让我们来看看 看看您是否继续这样使用通用 CRT。
根据文章 https://blogs.msdn.microsoft.com/vcblog/2015/03/03/introducing-the-universal-crt/ -
可以使用以下文件夹中的通用 crt dll 可分发文件启动您的应用程序:
C:\Program Files (x86)\Windows Kits\Redist\ucrt
列表中共有41个文件,总大小为1.8Mb。 (64 位平台示例)
当然这还不够,您还需要来自以下文件夹的 vcruntime140.dll & msvcp140.dll:
C:\Program Files (x86)\Microsoft Visual Studio 14.0\VC\redist\x64\Microsoft.VC140.CRT
因此,除了您的应用程序之外,您还将交付总共 43 个额外的 dll。
也可以在您的应用程序中静态编译 ucrt 库,之后您将不需要 43 个 dll - 但是 static link 是否会在 linking 之后 - 取决于你的应用程序 - 有多少 dll 和哪些 api 正在使用。 通常在 ucrt linked 到两个不同的 dll 之后,它们不一定彼此共享相同的全局变量——这可能会导致错误。
您需要 link 对抗 vcruntime.lib / msvcrt.lib,但这还不够 - 还有额外的 _VCRTIMP=
和 _ACRTIMP=
定义需要禁用从 ucrt 中提取函数的功能。
如果您使用的是 premake5,您可以像这样配置您的项目:
defines { "_VCRTIMP="}
linkoptions { "/nodefaultlib:vcruntime.lib" }
links { "libvcruntime.lib" }
其次是:
defines { "_ACRTIMP="}
linkoptions { "/nodefaultlib:msvcrt.lib" }
links { "libcmt.lib" }
Microsoft 未记录定义 - 因此将来可能会更改。
除了您自己的项目,您还需要重新编译您项目中使用的所有静态库。
至于 boost 库——我也成功编译了 boost,使用 b2.exe boostrapper
boost>call b2 threading=multi toolset=msvc-14.0 address-model=64 --stagedir=release_64bit --build-dir=intermediate_64but release link=static,shared --with-atomic --with-thread --with-date_time --with-filesystem define=_VCRTIMP= define=_ACRTIMP=
解决 linking 问题时 - 请注意未解析的 __imp*
函数名称来自 dllimport
关键字用法 -
如果你 link 反对 libvcruntime.lib,你不应该有任何 __imp*
引用。
我能够通过设置
C/C++ > Code Generation > Runtime Library
编译器选项
- 对于调试:从
/MDd
到/MTd
- 待发布:从
/MD
到/MT
这删除了所有 API-MS-WIN-CRT-*
和运行时 dll 引用并导致所有 CRT 代码静态链接。
有关新的 VS2015 通用 CRT(动态和静态)的详细信息,请参见此处: https://msdn.microsoft.com/en-us/library/abx4dbyh.aspx
我也在与静态 link 解决方案作斗争,该解决方案具有多个 components/project 库依赖项,从 MSVCRT、UCRT 和内核的各个部分导入函数。希望生成的 EXE 可以复制到需要的地方(它不是可以证明完整 MSI 安装合理的产品)。
在几乎放弃之后,我发现最好的解决方案是遵循隐藏在 Universal C Runtime announcement 中的指南,特别是:
We strongly recommend against static linking of the Visual C++ libraries, for both performance and serviceability reasons
只需删除您尝试过的所有 "special" linker 选项,返回 /MT|/MD(多线程 CRT DLL 发布|调试)运行时间库选择,它无处不在,例如较新的 Windows 10 个工作站、2012 R2 服务器和 Windows 7)。正如微软告诉我们的那样 install/redistribute MSVCRT (VC_Redist*.exe) and KB2999226 (UCRT via Windows Update),因为正如他们所说:
The Universal CRT is a component of the Windows operating system. It is included as a part of Windows 10, starting with the January Technical Preview, and it is available for older versions of the operating system via Windows Update.
因此,从逻辑上讲,我们的 C++ 解决方案为客户添加的唯一额外部署依赖项是 MSVCRT,因为 UCRT 应该已经存在于 up-to-date/well 维护的机器上。当然,这增加了一些不确定性;你不能只在任何机器上复制 EXE 和 运行,无论好坏。
如果您生成像 MSI 这样的像样的部署包,那么当您拥有像 WIX 这样的工具时,它很容易包含。另外需要注意的是,由于最近的 SDK 可以在本地包含 40 多个 DLL,但这不符合安全更新原则,所以我不会这样做。
这确实是唯一受支持的方法,see another example here。本文还建议我们 link 反对 "mincore_downlevel.lib" 这是一个重要的提示,对于您是否遇到这些 "api-ms-win*" 丢失的 DLL 错误至关重要。例如:
- 项目 SDK 版本设置为 10,link 且 mincore.lib = 仅在 Windows 10 上运行,而不是 8.1/2012 R2 或 Windows 7/2008 R2服务器。
- 项目 SDK 版本设置为 8.1,link,mincore.lib = 在 Windows 10 和 8.1/2012 R2 服务器上运行,但不在 Windows 7/2008 R2 服务器。
- 项目 SDK 版本设置为 10,link 和 mincore_downlevel.lib = 全部运行!
总结:
- 不要 link 静态,在项目设置中保留默认 DLL C 运行 次选择。
- 您不需要旧的 SDK,可以使用最新的 Windows 10 SDK 进行开发,但是您必须 link 使用 "mincore_downlevel.lib" 而不是 "mincore.lib" 如果需要支持旧的 Windows 版本。
- 为了便于使用,将此添加到您的 targetver.h 或 stdafx.h 中,这也记录了您的选择(删除另一行):
// Libraries
#pragma comment(lib, "mincore.lib") // Lowest OS support is same as SDK
#pragma comment(lib, "mincore_downlevel.lib") // Support OS older than SDK
我费了很大劲才找到 运行 2015 年 Visual Studio 构建的应用程序所需的 运行 时间 DLL。
在这里我发现了以下允许 VS-2015 构建的应用程序 运行。
- 从 https://www.microsoft.com/en-us/download/details.aspx?id=52685 下载可再发行组件
- 放置 msvcp140d.dll、vccorlib140d.dll、vcruntime140d.dll 和 ucrtbased.dll。
注意:根据您的系统处理器架构(x86、x64..)放置 dll 版本。
设置:配置属性 - 高级 - MFC 的使用 - "Use MFC in a Static Library" 对我有用(使用控制台应用程序 - 而不是 MFC/ATL 应用程序本身)。
如果您不想用自己的运行时替换运行时,那么是否
并不重要- 您有运行时键入 enabled/disabled
- 您有 C++ 异常 enabled/disabled
- 您是否将运行时库设置为多线程 DLL(将其设置为非 DLL 仍在将其构建到您的二进制文件中)
您唯一需要确保的是您不使用它的任何功能,并且Visual Studio自动不会link使用它. IE。没有断言,没有调用 string.h 或 stdio.h 中的任何内容,什么都没有。编译器可以用自己的内在函数替换的任何东西都可以,编译器检查也是如此 static_assert.