Visual studio 2015 run-time dependencies or how to get rid of Universal CRT?
Asked Answered
C

6

36

Compiled couple of .dll's using visual studio 2015, and tried to deploy on some older windows 7 / 64 bit. Tried also to guess which dll's are needed for application to start and copied MSVCP140.DLL & VCRUNTIME140.DLL - but application could not load vs2015 dll. Started to analyze what is wrong - and dependency walker showed dependencies from following dll's:

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

This was especially surprising since to my best understanding CRT is responsible for starting dll/exe, it does not provide any higher level services.

Ok, tried to figure out how to get rid of them or at least to minimize.

Found one article: https://blogs.msdn.microsoft.com/vcblog/2015/03/03/introducing-the-universal-crt/

It mentions about release static libraries - so I thought that I could link against them and get rid from *L1-1-0.DLL* dependency hell, but no matter what I have tried - I had no success. I've tried to link against libvcruntime.lib, libucrt.lib, libcmt.lib, tried to disable using linker option "/nodefaultlib:vcruntime.lib", and even tried to add include directory $(UniversalCRT_IncludePath), and also overriding some of define's as I have tried to guess they works - none of my attempts helped.

As an intermediate solution I've fall back to using Visual studio 2013, where CRT dll's are only two: msvcp120.dll, msvcr120.dll.

Of course you will probably recommend to install Visual studio 2015 run-times, but one of our requirement is to support standalone executable - which works without any installation - so additional installation is out of question for now.

Can you recommend me anything else than to wait Visual studio 2017 to arrive ?

Christoper answered 4/3, 2016 at 20:4 Comment(7)
The CRT does more than start the DLL or EXE, it provides the implementation of the entire C library a long with certain language and compiler features. Unless you rewrite your application to not use any of this, you need it all.Sellers
Ok, dispite of naming - crt was previously quite simple starter responsible for launching constructors / destructors - I know that because I have altered it's behavior already - see here: codeproject.com/Articles/442784/Best-gotchas-of-Cplusplus-CLI But is it so that in vs2015 they decided to explode msvcp140.dll, msvcr140.dll to 100 small dll's ?Christoper
No, the CRT has always been as I described. The file crtdll.c is just one small part of CRT, it also includes many other things like the implementation of printf as described in the Code Project article you linked. The only difference is now the CRT has been split up into separate libraries and DLLs. If you're why they did this, you can try reading the MSDN blog entry you linked in your post, along with the blog entries it refers to at the start. As a bonus, if you take the time to read it to the end you'll also find a solution to your problem.Sellers
I've actually found something that looks like a solution, but unfortunately it does not fully solves my problem, but I'll post it as answer here. Article itself does not highlights how project should be reconfigured correctly.Christoper
This is a defect in Dependency Walker, it has not been maintained in a very long time and does not know about recent Windows loader innovations. Like these MinWin forwarders. You need to stop using it. SysInternals' Process Monitor can tell you why it can't find a DLL that your program needs, you can see the program searching for the DLL as well as where it looks for it.Usquebaugh
From my perspective it's ok if .exe were able to load .dll successfully, but it was not. Btw - I agree with you that dependency walker show something odd - it shows a dependency on API-MS-WIN-CRT-*.dll's even thus their dll names are not explicitly listed in referring dll - try to search it with hex editor. So I suspect that load of VCRUNTIME140.DLL brought also other dll's as well even thus my dll does not directly depends on it.Christoper
We have a requirement to be able to run our application without any installation on windows 7 / 8 / 10. So far we've supplied crt dll's along with other .exe / .dll's - and executable were starting just fine. But now - universal crt - how to backport it to windows 7 / 8 - so no installation would not be required ? Does universal means that it will be forward compatible with windows 11 ? Or they will invent another super univeral compatible portable crt ?Christoper
C
7

(Updated 11.10.2016).

It's possible to get rid of universal CRT by linking it statically, I'll get to it later on, but let's take a look if you continue to use universal CRT as such.

According to article https://blogs.msdn.microsoft.com/vcblog/2015/03/03/introducing-the-universal-crt/ - it's possible to launch your application using universal crt dll distributables from following folder: C:\Program Files (x86)\Windows Kits\10\Redist\ucrt

There are 41 files totally in list with 1.8 Mb size in total. (example for 64-bit platform)

Of course it's not enough, you will need additionally vcruntime140.dll & msvcp140.dll coming from following folder: C:\Program Files (x86)\Microsoft Visual Studio 14.0\VC\redist\x64\Microsoft.VC140.CRT

So after that you will ship totally 43 additional dll's besides your application.

It's also possible to statically compile ucrt library inside your application after which you will not need 43 dll's - but whether static link will for after linking or not - depends on your application - how many dll's and which api's are in use. Generally after ucrt gets linked into two different dll's they don't necessarily share same globals with each other - which can results in errors.

You need to link against vcruntime.lib / msvcrt.lib, but it's not sufficient - there are extra _VCRTIMP= and _ACRTIMP= defines which needs to be disabled from pulling functions from ucrt.

If you're using premake5 you can configure your project like this:

defines { "_VCRTIMP="}
linkoptions { "/nodefaultlib:vcruntime.lib" }
links { "libvcruntime.lib" }

followed by:

defines { "_ACRTIMP="}
linkoptions { "/nodefaultlib:msvcrt.lib" }
links { "libcmt.lib" }

Defines are not documented by Microsoft - so it's possible that it's subject to change in future.

Besides your own projects, you will need to re-compile all static libraries which are in use in your projects.

As for boost libraries - I've managed to compile boost as well, using 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=

When troubleshooting linking problems - notice that unresolved __imp* function names from because of dllimport keyword usage - and if you link against libvcruntime.lib, you should not have any __imp* references.

Christoper answered 4/3, 2016 at 21:55 Comment(1)
Posted question to boost forum: sourceforge.net/p/boost/discussion/127795/thread/f74a4d33/…Christoper
P
43

No, you can't get rid of them, but I was able to statically-link to them by setting the C/C++ > Code Generation > Runtime Library compiler option

  • For Debug: from /MDd to /MTd
  • For Release: from /MD to /MT

This removed all the API-MS-WIN-CRT-* and runtime dll references and caused all the CRT code to be statically linked.

Details on the new VS2015 Universal CRT (dynamic and static) are here: https://msdn.microsoft.com/en-us/library/abx4dbyh.aspx

Note that the only other option is to compile with an older-compiler (like virus developers), not newer, because Microsoft promises same UCRT-requirements for any newer compiler-version as well.

Palmette answered 28/3, 2016 at 20:47 Comment(7)
Have you tested this on virtual machine or on actual windows 7 ? I have this setting by default in all projects - both debug and release configurations, but this does not solve the problem. Most interesting thing is that if you search with hex editor for API-MS-* string - you won't find it. But VCRUNTIME140.DLL has that dependency, and I guess it uses somehow altered load because dependency walker thinks it's my .exe dependency. But VCRUNTIME140.DLL references still API-MS* dll's. Must cut off VCRUNTIME140.DLL dependency.Christoper
Double check your project settings for /MT code generation. I have verified that the vcruntime140.dll reference disappears in this case.Palmette
Double checked by projects, you're right - I have used /MD. But as I recall /MT never worked out for me successfully - you see we use MFC, and MFC and /MT fights quite well with each other. But may be this was improved in vs2015 - maybe I'll try it again to link again. I sense long way of broken glass...Christoper
Ok, first of all I was wrong. And second of all - I was right. MFC can be linked, using /MT (premake5 config flag flags { "StaticRuntime" } ) - but /MT does not work well with managed code, which I was unfortunately in my own code. 2>cl : Command line error D8016: '/clr' and '/MT' command-line options are incompatibleChristoper
I believe this should be chosen as correct answer :)Carrnan
On Win10 with VS2017, by doing exactly what you suggested, I'm still getting the exact same problem.Titrate
Using CMAKE with Visual Studio, I found these settings in the CMakeSettings.json (I had to click "show advanced settings" to see them). -- There's more than one group of them though, there's a bunch of "C_FLAGS" settings, and then a break, and then lower down there's "CXX_FLAGS" settings. -- Make sure to change all of them!Upstretched
M
10

I too was fighting with statically linking a solution with multiple components/project library dependencies importing functions from various parts of the MSVCRT, UCRT and Kernel. The hope was the resulting EXE could be just copied around where it was needed (it was no product which would justify a full MSI installation).

After almost giving-up I found the best solution was the follow the guidelines hidden in the Universal C Runtime announcement, specifically:

We strongly recommend against static linking of the Visual C++ libraries, for both performance and serviceability reasons

Just remove all the "special" linker options you tried, drop-back to /MT|/MD (Multi-Threaded CRT DLL Release|Debug) runtime library choice and it works everywhere, e.g. newer Windows 10 workstations, 2012 R2 servers and Windows 7). Just install/redistribute MSVCRT (VC_Redist*.exe) and KB2999226 (UCRT via Windows Update) as Microsoft tell us to do, because as they also say:

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.

So logically the only additional deployment dependency our C++ solutions add for the customer is the MSVCRT, because the UCRT should already be there on up-to-date/well maintained machines. Of course it adds a bit of uncertainty; you can't just copy the EXE and run on any machine, good or bad.

If you produce a decent deployment package like an MSI then it's straightforward to include when you have tools like WIX. Also to note is since the recent SDK you can include the 40-odd DLLs locally, but that doesn't satisfy the security update principle so I wouldn't do that.

This is really the only supported way to do it, see another example here. This article also suggests we link against "mincore_downlevel.lib" which is an important tip, crucial to whether you get these "api-ms-win*" missing DLL errors. For example:

  1. Project SDK version set to 10, link with mincore.lib = Runs only on Windows 10, but not 8.1/2012 R2 or Windows 7/2008 R2 server.
  2. Project SDK version set to 8.1, link with mincore.lib = Runs on both Windows 10 and 8.1/2012 R2 server, but not Windows 7/2008 R2 server.
  3. Project SDK version set to 10, link with mincore_downlevel.lib = Runs on all!

In summary:

  1. Do not link statically, leave the default DLL C runtimes selected in the project settings.
  2. You don't need the old SDKs, can develop with the latest Windows 10 SDK, but you must link with "mincore_downlevel.lib" not "mincore.lib" if you want to support older Windows versions.
  3. For ease of use, add this to your targetver.h or stdafx.h which also documents your choice (remove the other line):
// Libraries
#pragma comment(lib, "mincore.lib")             // Lowest OS support is same as SDK
#pragma comment(lib, "mincore_downlevel.lib")   // Support OS older than SDK
Mobility answered 31/8, 2017 at 15:3 Comment(1)
Note that microsoft specifically state "Binaries that link to MinCore.lib or MinCore_Downlevel.lib are not designed to work on Windows 7, Windows Server 2008 R2 or earlier. Binaries that need to run on earlier versions of Windows or Windows Server must not use either MinCore.lib or MinCore_Downlevel.lib." msdn.microsoft.com/en-us/library/windows/desktop/…Gingergingerbread
C
7

(Updated 11.10.2016).

It's possible to get rid of universal CRT by linking it statically, I'll get to it later on, but let's take a look if you continue to use universal CRT as such.

According to article https://blogs.msdn.microsoft.com/vcblog/2015/03/03/introducing-the-universal-crt/ - it's possible to launch your application using universal crt dll distributables from following folder: C:\Program Files (x86)\Windows Kits\10\Redist\ucrt

There are 41 files totally in list with 1.8 Mb size in total. (example for 64-bit platform)

Of course it's not enough, you will need additionally vcruntime140.dll & msvcp140.dll coming from following folder: C:\Program Files (x86)\Microsoft Visual Studio 14.0\VC\redist\x64\Microsoft.VC140.CRT

So after that you will ship totally 43 additional dll's besides your application.

It's also possible to statically compile ucrt library inside your application after which you will not need 43 dll's - but whether static link will for after linking or not - depends on your application - how many dll's and which api's are in use. Generally after ucrt gets linked into two different dll's they don't necessarily share same globals with each other - which can results in errors.

You need to link against vcruntime.lib / msvcrt.lib, but it's not sufficient - there are extra _VCRTIMP= and _ACRTIMP= defines which needs to be disabled from pulling functions from ucrt.

If you're using premake5 you can configure your project like this:

defines { "_VCRTIMP="}
linkoptions { "/nodefaultlib:vcruntime.lib" }
links { "libvcruntime.lib" }

followed by:

defines { "_ACRTIMP="}
linkoptions { "/nodefaultlib:msvcrt.lib" }
links { "libcmt.lib" }

Defines are not documented by Microsoft - so it's possible that it's subject to change in future.

Besides your own projects, you will need to re-compile all static libraries which are in use in your projects.

As for boost libraries - I've managed to compile boost as well, using 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=

When troubleshooting linking problems - notice that unresolved __imp* function names from because of dllimport keyword usage - and if you link against libvcruntime.lib, you should not have any __imp* references.

Christoper answered 4/3, 2016 at 21:55 Comment(1)
Posted question to boost forum: sourceforge.net/p/boost/discussion/127795/thread/f74a4d33/…Christoper
D
2

I was too struggled a lot finding out the run time DLLs required to run an application which was built in Visual Studio 2015.

Here I found the following things which allow VS-2015 built application to run.

Note : Place the dlls versions according to your system processor's architecture(x86, x64..).

Despondent answered 13/2, 2018 at 5:22 Comment(0)
F
2

Setting: Configuration Properties - Advanced - Use of MFC - "Use MFC in a Static Library" worked for me (with a console application - not a MFC/ATL application per-se).

Fischer answered 11/3, 2020 at 17:53 Comment(1)
I did this and my runtime errors of the kind "api-ms-win-xxx.dll missing" turned into linktime errors of the kind "__imp__SetBkMode" missing. (Don't ask me how this makes sense.) I then knew where to look and I solved my problem right away.Merriemerrielle
P
0

If you're not trying to replace the Runtime with your own then it doesn't matter whether

  • You have Runtime Typing enabled/disabled
  • You have C++ Exceptions enabled/disabled
  • Whether you have the Runtime Library set to Multithreaded DLL or not (setting it to non-DLL is still building it into your binary)

The only thing you need to ensure is that you don't use any of its capabilities and Visual Studio automatically doesn't link to it. Ie. No asserts, no calls to anything in string.h or stdio.h, nothing. Anything the compiler can replace with its own intrinsics tho is ok, as are compiler checks like static_assert.

Pater answered 18/1, 2021 at 2:33 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.