Navigating the Visual C++ Runtime Library Variants

Each release of Visual Studio provides several variants of its C/C++ runtime libraries. Choosing the right libraries on the development side, and getting the right DLLs installed on the test or deployment side, are not new problems but they are nonetheless a perennial cause of confusion. This article gives a quick overview of what you need to know.

The Library Variants

There are four variants of C/C++ runtime library you can build your code against:

  • Multi-threaded Debug DLL
  • Multi-threaded DLL
  • Multi-threaded Debug
  • Multi-threaded

You can select which library you’re using by right-clicking on your project in Visual Studio and selecting Properties, clicking the Code Generation option under C/C++ on the dialog that pops up, and going to the Runtime Library property.

Visual Studio C/C++ Code Generation Properties

Remember that this setting is per-configuration, as you’ll want to choose a Debug runtime library for a Debug configuration, and Release runtime library for a Release configuration.

What’s the difference?

The DLL runtime library options mean that you link dynamically against the C/C++ runtime, and for your program to run, that DLL will need to be somewhere your program can find it (more on that later).

The options not mentioning DLL (Multi-threaded Debug and Multi-threaded Release) cause your program to be statically-linked against the runtime. This means that you don’t need an external DLL for the program to be run, but your program will be bigger because of the extra code, and there are other reasons why you might not want to choose it.

By default, when you create a new project in Visual Studio, it will use the DLL runtime.

The multi-threaded in the runtime names is a legacy of when there used to be both non-thread-safe and multi-threaded C/C++ runtimes. You’ll always be using a multi-threaded runtime with modern Visual Studio, even if your own application is single-threaded.

Deploying DLL Runtimes

If you’re linking against the DLL runtimes, then you’ll have to think about how to deploy them when releasing your program (to Test, and to your customers).

If you deliver Debug builds to your Test team, make sure you provide the Debug variant of the DLL runtimes too.

Also, don’t forget to get the right architecture (e.g. x86 vs x64).

Redistributable Installers

Microsoft provide redistributable packages that install the Release (but not the Debug) DLLs. These can be found easily enough by searching for something like Visual C++ Redistributable 2013 (substituting the Visual Studio version for what you need). You can also go straight to “Latest Supported Visual C++ Downloads” on Microsoft’s website.

These redistributables packages are executables, and you can call them from your program’s installer (or you could run them manually for setting up a test environment). Note that there are separate redistributables for x86 and x64.

Merge Modules

If you’re building an MSI installer, you can merge the Merge Module for the C/C++ runtime you’re using into your installer package. These merge modules are typically found in C:\Program Files (x86)\Common Files\Merge Modules. For example, the x86 C/C++ runtime’s merge module for Visual Studio 2013 is called Microsoft_VC120_CRT_x86.msm.

Note that the version numbers in these merge module names are not the year-based product versions, but the internal version numbers. This table on Wikipedia shows the mapping between the version numbers for avoidance of confusion.

Unlike the stand-alone executable redistributable installers above, the merge modules also come in Debug variants.

Some versions of Visual Studio have support for a Visual Studio Installer project type (under the Setup and Deployment category in Other Project Types), and if you include the output from your program’s projects in one of these installers, the merge modules for the runtime will be included automatically. You can also use this as a trick to get an installer that will install the Debug runtimes for internal testing purposes (any dummy C/C++ project will do, it doesn’t have to actually install your program).

Copy From Redist Folder

You can also just copy the DLLs from the redist folder in your Visual C++ installation into where your program is installed. For example, for Visual Studio 2013, you’ll find the x64 C/C++ runtime libraries somewhere like C:\Program Files (x86)\Microsoft Visual Studio 12.0\VC\redist\x64\Microsoft.VC120.CRT\.

The debug variants can be found somewhere like C:\Program Files (x86)\Microsoft Visual Studio 12.0\VC\redist\Debug_NonRedist.

(Adjust paths as appropriate for your Visual Studio version and installation location).

Mixing C/C++ Runtimes

In an ideal world, you would use the same C/C++ runtime library variant (Debug vs Release, DLL vs statically-linked), and all from the same version of Visual Studio, for all libraries being linked into your program.

If you do mix runtimes, you may get linker errors, your program may simply fail to run at all, or worse still, it may seem to be working but crash or give the wrong result only in some cases.

Ignoring Default Libraries

A common scenario is that you only have the Release version of some third-party library, but you still want to be able to build the Debug variant of your own code using this library. Another scenario is that you have a library that uses the static C/C++ runtime and you want the DLL version in your program, or the reverse.

If the third-party library is C code then you’ll probably be able to get away with this and have it actually work, using the /NODEFAULTLIB linker option.

If the library is C++ code, you are probably out of luck as too much of the generated code is tied to symbols in a particular runtime.

These are the different library names:

  • LIBCMT.LIB: Statically-linked Release runtime (a.k.a. Multi-threaded)
  • LIBCMTD.LIB: Statically-linked Debug runtime (a.k.a. Multi-threaded Debug)
  • MSVCRT.LIB: Dynamically-linked Release runtime (a.k.a. Multi-threaded DLL)
  • MSVCRTD.LIB: Dynamically-linked Debug runtime (a.k.a. Multi-threaded Debug DLL)

Remember, the runtime libraries you want to ignore are the ones that the third-party code is using, i.e. it will be different from the library that your own program is using. If you look at your build output you will be prompted to choose the right one anyway, e.g.:

LINK : warning LNK4098: defaultlib 'LIBCMTD' conflicts with use of other libs; use /NODEFAULTLIB:library

You can specify the library to ignore by right-clicking on your project, selecting Properties, clicking the Input entry under Linker and adding the runtime library name into the Ignore Specific Default Libraries entry.

Visual Studio Ignore Default Libraries

Crossing Module Boundaries

You can also run into C/C++ runtime mismatch problems in more subtle ways across module boundaries (between an EXE and a DLL it loads for example).

For example, data structures in the C library may be defined differently by different runtimes. I’ve seen this cause crashes in programs that used a DLL that made use of a FILE* in its API. A file is opened in one module using one C runtime, and interacted with by another module which has a different, incompatible implementation. Safer options would include passing Windows API HANDLE objects for things like this, or else wrapping up the file interactions in a way that is runtime-agnostic.

Different runtimes also use their own memory heap for allocations. If an object is allocated in one module on one heap, but deallocated in another module, a crash is likely to occur if the C/C++ runtimes are mismatched. This only applies of course to allocations using the C or C++ runtime such as malloc or new. If the default Windows process heap is being used everywhere, for example, everything is fine.

Note that if the modules statically link against the C/C++ runtime, they will have this problem even if it was the same variant of the runtime they linked against, because there will still be two different runtimes with their own memory heaps in play. Therefore, you will want to use the DLL C/C++ runtime in such circumstances.

It would also be wise to use the (same version of) DLL runtimes in each module if runtime-implemented functionality like exceptions or classes with vtables cross the module boundaries, though some combinations of mismatch may work in practice.

Share on FacebookTweet about this on TwitterShare on Google+Share on LinkedInEmail this to someonePrint this page

Comments are closed