Visual Studio 2015运行时依赖项或如何摆脱Universal CRT?

Tar*_*aro 24 c++ msvcrt visual-studio-2015

编译了几个.dll使用visual studio 2015,并试图部署在一些旧的Windows 7/64位上.试图猜测应用程序启动和复制MSVCP140.DLL和VCRUNTIME140.DLL需要哪些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
Run Code Online (Sandbox Code Playgroud)

这是特别令人惊讶的,因为我最好的理解CRT负责启动dll/exe,它不提供任何更高级别的服务.

好的,试图弄清楚如何摆脱它们或至少最小化.

找到一篇文章:https: //blogs.msdn.microsoft.com/vcblog/2015/03/03/introducing-the-universal-crt/

它提到了发布静态库 - 所以我认为我可以链接它们并摆脱*L1-1-0.DLL*依赖地狱,但无论我尝试过什么 - 我都没有成功.我试图链接libvcruntime.lib,libucrt.lib,libcmt.lib,尝试禁用链接器选项"/nodefaultlib:vcruntime.lib",甚至尝试添加include目录$(UniversalCRT_IncludePath),并覆盖一些定义的,因为我试图猜测它们是有效的 - 我的尝试都没有帮助.

作为一个中间解决方案,我回归到使用Visual Studio 2013,其中CRT dll只有两个:msvcp120.dll,msvcr120.dll.

当然,您可能会建议安装Visual Studio 2015运行时,但我们的要求之一是支持独立可执行文件 - 无需任何安装即可运行 - 因此现在无法进行额外安装.

除了等待Visual Studio 2017到货之外,你能推荐我吗?

Ton*_*oij 28

我能够通过设置C/C++ > Code Generation > Runtime Library编译器选项来解决这个问题

  • 对于Debug:from /MDdto/MTd
  • 发布:从发布/MD/MT

这删除了所有API-MS-WIN-CRT-*和运行时dll引用,并导致所有CRT代码静态链接.

有关新VS2015通用CRT(动态和静态)的详细信息,请访问:https://msdn.microsoft.com/en-us/library/abx4dbyh.aspx

  • 您在虚拟机或实际 Windows 7 上测试过吗?我在所有项目中默认都有此设置 - 调试和发布配置,但这并不能解决问题。最有趣的是,如果您使用十六进制编辑器搜索 API-MS-* 字符串 - 您将找不到它。但 VCRUNTIME140.DLL 具有这种依赖关系,我猜它使用了某种改变的负载,因为依赖关系遍历器认为这是我的 .exe 依赖关系。但 VCRUNTIME140.DLL 仍然引用 API-MS* dll。必须切断 VCRUNTIME140.DLL 依赖。 (2认同)
  • 好的,首先我错了.第二个 - 我是对的.可以使用/ MT(premake5配置标志标志{"StaticRuntime"})链接MFC - 但是/ MT不能很好地使用托管代码,我很遗憾地在我自己的代码中.2> cl:命令行错误D8016:'/ clr'和'/ MT'命令行选项不兼容 (2认同)

Ton*_*all 9

我也正在努力将一个解决方案与多个组件/项目库依赖关系静态链接,从MSVCRT,UCRT和内核的各个部分导入函数.希望是最终的EXE可以被复制到需要它的地方(它不是可以证明完整的MSI安装的产品).

几乎放弃后,我发现最好的解决方案是遵循Universal C Runtime公告中隐藏的指导原则,具体来说:

出于性能和可维护性的原因,我们强烈建议不要使用Visual C++库的静态链接

只需删除您尝试的所有"特殊"链接器选项,回退到/ MT |/MD(多线程CRT DLL发布|调试)运行时库选项,它可以在任何地方使用,例如较新的Windows 10工作站,2012 R2服务器和Windows 7).只需像微软告诉我们那样安装/重新分发MSVCRT(VC_Redist*.exe)KB2999226(通过Windows Update进行UCRT),因为他们也说:

Universal CRT是Windows操作系统的一个组件.它作为Windows 10的一部分包含在1月技术预览版中,并且可通过Windows Update用于旧版操作系统.

从逻辑上讲,我们的C++解决方案为客户添加的唯一额外部署依赖是MSVCRT,因为UCRT应该已经存在于最新/维护良好的机器上.当然它增加了一点不确定性; 你不能只是复制EXE并在任何机器上运行,无论好坏.

如果您像MSI一样生成一个像样的部署包,那么当您拥有像WIX这样的工具时,可以直接包含它.另外要注意的是,从最近的SDK开始,你可以在本地包含40多个DLL,但这不符合安全更新原则,所以我不会这样做.

这实际上是唯一支持的方法,请参见此处的另一个示例.本文还建议我们链接"mincore_downlevel.lib",这是一个重要提示,对于您是否获得这些"api-ms-win*"缺失的DLL错误至关重要.例如:

  1. Project SDK版本设置为10,与mincore.lib链接=仅在Windows 10上运行,但不在8.1/2012 R2或Windows 7/2008 R2服务器上运行.
  2. Project SDK版本设置为8.1,与mincore.lib链接=在Windows 10和8.1/2012 R2服务器上运行,但不在Windows 7/2008 R2服务器上运行.
  3. Project SDK版本设置为10,与mincore_downlevel.lib链接=全部运行!

综上所述:

  1. 不要静态链接,保留在项目设置中选择的默认DLL C运行时.
  2. 您不需要旧的SDK,可以使用最新的Windows 10 SDK进行开发,但如果要支持较旧的Windows版本,则必须链接"mincore_downlevel.lib"而不是"mincore.lib".
  3. 为了便于使用,请将它添加到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
Run Code Online (Sandbox Code Playgroud)

  • 请注意,微软特别声明“**链接到 MinCore.lib 或 MinCore_Downlevel.lib 的二进制文件不适用于 Windows 7、Windows Server 2008 R2 或更早版本**。需要在早期版本的 Windows 或 Windows Server 上运行的二进制文件不得使用 MinCore.lib 或 MinCore_Downlevel.lib。” https://msdn.microsoft.com/en-us/library/windows/desktop/dn505783(v=vs.85).aspx (2认同)

Tar*_*aro 6

(更新11.10.2016)。

通过静态链接可以消除通用CRT,稍后再讲,但是让我们看一下是否继续使用通用CRT。

根据文章https://blogs.msdn.microsoft.com/vcblog/2015/03/03/introducing-the-universal-crt/-可以使用以下文件夹中的通用crt dll可分发文件来启动您的应用程序: C:\Program Files (x86)\Windows Kits\10\Redist\ucrt

列表中共有41个文件,总大小为1.8 Mb。(以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,但是链接后是否需要静态链接取决于您的应用程序-使用了多少个dll和哪个api。通常,将ucrt链接到两个不同的dll之后,它们不一定彼此共享相同的全局变量-这可能会导致错误。

您需要针对vcruntime.lib / msvcrt.lib进行链接,但这还不够-有更多内容_VCRTIMP=_ACRTIMP= 定义了哪些功能需要禁止从ucrt中提取函数。

如果您使用的是premake5,则可以这样配置项目:

defines { "_VCRTIMP="}
linkoptions { "/nodefaultlib:vcruntime.lib" }
links { "libvcruntime.lib" }
Run Code Online (Sandbox Code Playgroud)

其次是:

defines { "_ACRTIMP="}
linkoptions { "/nodefaultlib:msvcrt.lib" }
links { "libcmt.lib" }
Run Code Online (Sandbox Code Playgroud)

Microsoft没有记录定义-因此将来可能会对其进行更改。

除了您自己的项目外,您还需要重新编译项目中正在使用的所有静态库。

至于Boost库-我也设法使用b2.exe boostrapper编译了boost

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=

在对链接问题进行故障排除时-请注意,__imp*由于dllimport使用了关键字而导致无法解析的函数名-并且如果针对libvcruntime.lib进行链接,则不应有任何__imp*引用。