Search code examples
c++visual-studio-2015msvcrt

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


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 ?


Solution

  • (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.