« No Country For Old Men | Home | TV-B-GONE: CES Edition »

Individual Entry With Comments


January 12, 2008

Choosing the Correct C/C++ Runtime Library

Filed under Programming

The C/C++ runtime library contains basic functions like memory allocation (malloc, new), output (printf), and string manipulation (strcpy, strlen).

When building a C/C++ application or library, you must pick a C/C++ runtime library. In Visual Studio 2005, you can select this option using Project->Properties...->Configuration Properties->C/C++->Code Generation->Runtime Library:

image

You have 4 versions:

  1. Multi-threaded (/MT)
  2. Multi-threaded Debug (/MTd)
  3. Multi-threaded DLL (/MD)
  4. Multi-threaded DLL Debug (/MDd)

The C++ runtime library is dependent on the C runtime library. The C runtime library version must match the C++ runtime library version.  Thus, these options apply to both the C and C++ runtime libraries.

In previous versions of Visual Studio, you had additional options that were single-threaded. These versions would execute faster on a single core than the multi-threaded versions. However, they were not safe to use in a multi-threaded application. I'm guessing these libraries were dropped since multiple cores are quickly becoming ubiquitous and multi-threaded applications are needed to take advantage of these extra cores.

These four choices are all the permutations from two variables:

  • Debug vs. Release
  • DLL vs. Static Library

The first variable is easy. Use Debug on internal software that is not shipped to customers. The debug runtime library *can't* be included with your application legally. Just to be clear, you *can* ship a debug version of your application to a customer, but it should use the *release* version of the runtime library.

The Debug runtime library gives you access to some helpful debugging aids for error reporting and tracking down memory leaks. See the additional debug functionality you get with this version of the runtime library (and macro _DEBUG defined) here.

The next variable is DLL or Static Library. In general, you should use DLL. You might consider the Static Library version if:

  • You have a small application and you don't want to waste memory with runtime library calls you don't need
  • You want a simple application that is not dependent on shipping with an additional runtime library DLL.

The above instructions work well if your application doesn't use any other libraries. That rarely happens. Microsoft has several vague warnings in their documentation about using more than one version of runtime in an application.

The goal is to use one runtime library throughout your entire application.

That is nearly impossible since you typically don't have control of which runtime library other libraries use. For example, OpenGL uses the runtime library. If your application or any other libraries you use don't use the same runtime library as OpenGL, then you are mixing runtime libraries.

How do you know what runtime library a .EXE, .DLL or shared library (.LIB), or .OBJ use? Use this command line:

dumpbin /all XXXX | find /i "msvcr"

...and replace XXXX with the .EXE, .DLL, .LIB (for static libraries...not the stub for .DLL's), or .OBJ in question. You should get something similar to this:

image

You can use the results from this command with this page to see which runtime library you should use.

If you don't get any output, then it likely means that a static runtime library is used.

Even with information about what runtime libraries are in use, you may find it impossible to make your application use a single runtime library. If you match the runtime libraries, it is possible that one library uses the Visual Studio 7.0 version of the runtime library (msvcr70.dll) but you only have access to Visual Studio 8.0 (msvcr80.dll).

So now what?

It turns out is is OK to mix runtime libraries *except* in certain cases. A well written library should avoid these cases and then it doesn't matter if the runtime libraries match. Libraries that cannot avoid these cases should ship with 4 versions of their libraries that match the 4 versions of the runtime libraries.

Here is a good article with examples of situations to avoid so that you don't have to worry about mixing runtime libraries.

Choosing a runtime library summary...

  • Use the debug version only internally, release for anything that could be used by customers
  • Use the DLL version except in special situations
  • Use consistent settings throughout your project (the runtime library setting can be done per source file)
  • Don't worry if your runtime library settings match other libraries you use (unless the library comes in multiple runtime library versions)

Comments (15)

Bubba:

You lost me at Hello World!

Rich:

Dave, I've got 3 dlls that I use for jni calls from Java. When built with the IDE (VS 8) they work fine. I copied the command lines for the compiler and linker out of the IDE and put them in a Makefile and built the dlls. They no longer work. They cannot find msvcp80.dll (at run-time). If I compile with /MT instead of /MD, the first 2 dlls find msvcp80.dll OK, but the third dll which links with the first 2 dlls, won't link. It can't find any of the symbols from msvcp80.dll. Catch-22.

I'm obviously missing something. How do I tell the linker to link with either msvcp80.dll or tell it what the path to that dll is? What is the IDE doing in the build that the Makefile is missing?

@Rich:

Sounds like the IDE is embedding a manifest that tells where to find msvcp80.dll, but you aren't doing that step from the command line.

I did a write-up on manifests here.

To verify this, load the IDE-generated DLL (the one that works) in Dependency Walker and see if it is using msvcp80.dll from the \windows\winsxs directory.

Next check the command line-generated DLL (the one that doesn't work) in Dependency Walker. See if msvcp80.dll is missing the \windows\winsxs path. If it is, you are missing a manifest file.

After you build and link, Visual Studio also embeds the manifest file (which tells the application where to get msvcp80.dll from). You can do this from the command line using mt.exe. See mt.exe /? for help on using mt.exe.

Let me know how it goes.

David

Rich:

That was it. There is a paragraph in the IDE, Project->Properties->Manifest Tool->Command Line. I saw it before but did not pursue it. I've read a little about the SxS stuff. As clear as pond water. Dlls were broken, so they broke them more. And then some more. And then, etc.

Thanks for the quick response. I need an automated build (5 platforms going on 6).

Hi, David.

First, thank you for a great blog. :)

I've got this 3rd party library added to my Visual Studio 2005 SP1 project as Delay Loaded DLLs (plugin). As soon as my program tries to call 'new' or 'delete' it tries to load one of these DLLs. As a test, I made a simple x64 /MD(d) Console testproject with the following main:

int main(int argc, char* argv[])
{
char* pBuf = new char[42];
delete[] pBuf;

return 0;
}

This is all the code in the project. (No static objects etc..) So there is no code using the DLLs at all but it still tries to load one of them. I assume it's looking for a runtime. When I link the application all of the DLLs with the exception of the one it tries to load comes up with the following warning:
1>LINK : warning LNK4199: /DELAYLOAD:SomeDLL.dll ignored; no imports found from SomeDLL.dll


From the embedded manifest of my debug exe version:

assemblyIdentity type="win32"
name="Microsoft.VC80.DebugCRT"
version="8.0.50727.762"
processorArchitecture="amd64"
publicKeyToken="1fc8b3b9a1e18e3b"

assemblyIdentity type="win32"
name="Microsoft.VC80.CRT"
version="8.0.50727.762"
processorArchitecture="amd64"
publicKeyToken="1fc8b3b9a1e18e3b"


And the DLL it tries to load:

assemblyIdentity type="win32"
name="Microsoft.VC80.CRT"
version="8.0.50608.0"
processorArchitecture="amd64"
publicKeyToken="1fc8b3b9a1e18e3b"


Do you have any idea why it tries to load the runtime from one of the DLL's and not from the /MD(d) runtime option I've used?

- Frode

Frode,

It's hard for me to know what the issue is here without the project in front of me.

This is what I'd do if I was you...

Use dependency walker to see which dll is bringing in which libraries. You can "profile" your app and see when new libraries are brought in at runtime and why. Use the "C:" button to see the full path to the libraries.

Dependency Walker should be able to answer all your questions about what dll's you have, which ones are being delayed loaded and not, and all the dependencies a dll has.

Good luck!

David

Rahul:

Hello David,
Thanks for taking some time out to write a good article on C Runtime libraries. I have a question concerning CRT's and I hope you could take some time out to answer them.
1.I have a solution which has most of the projects generating static libraries and the Runtime setting is /MDd or /MD based on debug or release build. If I'm to build an application which references these these static libraries What should be the runtime setting for the application vcproj?
2. If I set the runtime setting for the vcproj as /MDd then it results in the following "runtime error R6030 CRT not intialized" and if I set the runtime settnig to /MTd then this results in a memory access violation once the program procedure ends (exit code executed before end of main()).
Any suggestions from your end that could help resolve the issue.
Thanks in advance,
-Rahul

@Rahul:

1. You should use the same /MD or /MDd as your static libraries.

2. This issue doesn't sound related to your choice of runtime libraries. The help page for R6030 indicates you are bypassing the normal startup code that initializes the C runtime library. I'd look into why this is happening (probably via a /ENTRY linker switch).

rock g:

Thanks a lot for the post! I have a project that wouldn't compile because one of the static lib i use is apparently of different runtime library. (but i can't get it using dumpbin)

"Don't worry if your runtime library settings match other libraries you use (unless the library comes in multiple runtime library versions)"

You've lost me here, from your last comment, you say that the same /MD or /MDd should be used as the static libraries the project uses. So do we really need to care?

@rock g:

Ultimately your project should all use the same runtime libraries. But that is virtually impossible if every library you link to doesn't have a debug/release and static/dll versions for the runtime library it uses.

So the best you can do is make sure all *your* code uses the same runtime library and matches one of your 3rd party libraries.

If there is still a problem, the linker will complain that runtime library symbols were already defined (LNK2005). To fix this, just add a /NODEFAULTLIB:LIBRARY_NAME.lib.

Good luck!

Viru:

nice and precise information posted !

Thalis:

Please Help!!! I keep getting the C++ runtime library error - CRT not initialised! Many programs as a result cannot be executed.

Sorry for asking like this, but I am not a programmer and I am at a loss as to how to fix it. Is there anything I can do?

Your help is greatly appreciated.

Thanks for posting this information, very helpful! I know if you compile in MT and release mode, you can use the .exe file on other computers that do not have visual studio.

David, thanks for the clear explanation of the CRTs and how to make sense of them. In my project, I'm trying to build a static C library linked against a DLL CRT (I used /MDd). Your dumpbin command above showed the expected output, but I also tried using dumpbin /dependents and dumpbin /imports, and neither of those commands seem to indicate a dependency on the DLL version of the CRT. Why not? Also, I've posted this same question on SO here: http://stackoverflow.com/questions/9947589/windows-c-runtime-library-not-linking-like-i-expect

YB:

Thanks Dave for the great blog!!!

Post a comment

(If you haven't left a comment here before, you may need to be approved by the site owner before your comment will appear. Until then, it won't appear on the entry. Thanks for waiting.)


About

This page contains a single entry from the blog posted on January 12, 2008 2:50 PM.

The previous post in this blog was No Country For Old Men.

The next post in this blog is TV-B-GONE: CES Edition.

Many more can be found on the main index page or by looking through the archives.

Powered by
Movable Type 3.34