views:

488

answers:

3

Problem:

I'm trying to use a library named DCMTK which used some other external libraries ( zlib, libtiff, libpng, libxml2, libiconv ). I've downloaded these external libraries (*.LIB & *.h files ) from the same website. Now, when I compile the DCMTK library I'm getting link errors (793 errors) like this:

Error   2   error LNK2005: __encode_pointer already defined in MSVCRTD.lib(MSVCR90D.dll)    LIBCMTD.lib dcmmkdir 
Error   3   error LNK2005: __decode_pointer already defined in MSVCRTD.lib(MSVCR90D.dll)    LIBCMTD.lib dcmmkdir 
Error   4   error LNK2005: __CrtSetCheckCount already defined in MSVCRTD.lib(MSVCR90D.dll)  LIBCMTD.lib dcmmkdir 
Error   5   error LNK2005: __invoke_watson already defined in MSVCRTD.lib(MSVCR90D.dll) LIBCMTD.lib dcmmkdir 
Error   6   error LNK2005: __errno already defined in MSVCRTD.lib(MSVCR90D.dll) LIBCMTD.lib dcmmkdir 
Error   7   error LNK2005: __configthreadlocale already defined in MSVCRTD.lib(MSVCR90D.dll)    LIBCMTD.lib dcmmkdir 
Error   8   error LNK2005: _exit already defined in MSVCRTD.lib(MSVCR90D.dll)   LIBCMTD.lib dcmmkdir 

Documentation:

This seems to be a popular error for this library so, they do have a FAQ entry addressing this issue which ( http://forum.dcmtk.org/viewtopic.php?t=35 ) says:

  • The problem is that the linker tries to combine different, incompatible versions of the Visual C++ runtime library into a single binary.
  • This happens when not all parts of your project and the libraries you link against are generated with the same code generation options in Visual C++.
  • Do not use the /NODEFAULTLIB workaround, because strange software crashes may follow. Fix the problem!

  • DCMTK is by default compiled with the "Multithreaded" or "Multithreaded Debug" code generation option (the latter for Debug mode).

  • Either change the project settings of all of your code to use these code generation options,
  • or change the code generation for all DCMTK modules and re-compile.
  • MFC users beware: DCMTK should be compiled with "Multithreaded DLL" or "Multithreaded DLL Debug" settings if you want to link the libraries into an MFC application.

Solution to same problem for others:

http://stackoverflow.com/questions/2259697/vscopengl-huge-amount-of-linker-issues-with-release-build-only says:

It seems that your release build is trying to link to something that was built debug. You probably have a broken dependency in your build, (or you missed rebuilding something to release by hand if your project is normally built in pieces).

More technically, you seem to be linking projects built with different C Run Time library settings, one with "Multi-Threaded", another one with "Multi-Threaded Debug". Adjust the settings for all the projects to use the very same flavour of the library and the issue should go away

Questions:

Till now I used to think that Name mangling is the only problem that may cause linking failures if its not been standardized. Just now I knew there are other things also which can cause same effect.

  1. Whats up with the "Debug Mode" (Multi-Threaded Debug) and "Release Mode" (Multi-Threaded)? What exactly is happening under the hood? Why exactly this thing is causing linking error?

  2. I wonder if there is something called "Single-Threaded Debug" and "Single-Threaded" which again causes the same thing.

  3. Documentation talks something about "Code Generation Options". What Code Generation Options? WTH are they?

  4. Documentation specifically warns us not to use /NODEFAULTLIB workaround. (example /NODEFAULTLIB :msvcrt ). Why? How would I cause troubles? what exactly is it?

  5. Please explain the last point in the documentation for MFC users. Because I'm going to use MFC later in this project. Explain Why should we do it? What troubles would it cause if I don't.
  6. Anything more you'd like to mention? I mean regarding similar errors. I'm very interested in Linker & its problems. So, if there are any similar things you can mentions them or some keywords atleast.
A: 

Whats up with the "Debug Mode" (Multi-Threaded Debug) and "Release Mode" (Multi-Threaded)? What exactly is happening under the hood? Why exactly this thing is causing linking error?

They are different versions of the C runtime library. You can statically link to the runtime library in debug and release mode. In the Code Generation Options (mentioned below), those would be "Multi-Threaded Debug" and "Multi-Threaded". The options "Multi-Threaded Debug DLL" and "Multi-Threaded DLL" dynamically link to the C runtime. By dynamically linking to the runtime, you'll also have to ship your installer configured to install the VC redistributable package that contains the proper runtime dlls for your version of Visual C++.

Statically linking to the C runtime is generally frowned upon, even by Microsoft:

In addition to all the methods described above of distributing the Visual C++ libraries DLLs, there is one last option for building your application which does not require you to distribute the DLLs. However, this option only works for native-only code (it is not supported with /clr) and leaves your customers seriously vulnerable to any security holes as well as adds a significant burden upon yourself to patch all customer systems should a vulnerability be found in any of the libraries. This option is to statically link in the libraries as .lib files instead of dynamically loading them as DLLs. You do this by using the /MT flag on the cl.exe command line (vs /MD), or selecting the appropriate option in your project properties through Visual Studio. You may wish to use this option when testing early debug builds of your application on test machines before you start working on setup. [See footnote 3]

However, I can think of no scenarios in which this is actually the right thing to do when shipping your product to customers. Basically, what this approach does is pulls in the binary code needed from .LIB files at compile time, making it a part of your .exe or .dll files. It increases the size of your application, and there is no way to update the libraries apart from recompiling your application with new .LIBs and redistributing your application all over again. What this means is that unless you go touch every single machine which has installed your application every time there is a security vulnerability found in the Visual C++ libraries and completely reinstall your updated binaries, you will be leaving your customers vulnerable to attack. If instead you use the DLLs, every time there is a security vulnerability found in the Visual C++ libraries, Microsoft will install the update centrally into the WinSxS folder via Windows Update and all requests for the DLLs will be redirected to the updated version. This removes all servicing burden on your side and also allows the user to install one small update which will touch all their applications instead of replacing every installed exe and DLL on their system. Please, do not distribute an application built by linking statically against the Visual C++ libraries unless you have a system in place for updating every customer machine and also have a very good reason to do so. At this time, I can think of no circumstance under which this would be the right thing to do for a shipping application.


I wonder if there is something called "Single-Threaded Debug" and "Single-Threaded" which again causes the same thing.

No such thing, see above.


Documentation talks something about "Code Generation Options". What Code Generation Options? WTH are they?

Right click on your Visual C++ project (from within Visual Studio) and select Properties. Under Configuration Properties->C/C++->Code Generation


Documentation specifically warns us not to use /NODEFAULTLIB workaround. (example /NODEFAULTLIB :msvcrt ). Why? How would I cause troubles? what exactly is it?

Take their advice and don't do it.


Please explain the last point in the documentation for MFC users. Because I'm going to use MFC later in this project. Explain Why should we do it? What troubles would it cause if I don't.

Because MFC is dynamically linked to the C runtime, using libraries that are statically linked to the C runtime will cause the linker errors you listed first in your post.


Anything more you'd like to mention? I mean regarding similar errors. I'm very interested in Linker & its problems. So, if there are any similar things you can mentions them or some keywords atleast.

From my experience, always dynamically link to the C runtime. It generally saves you a lot of headaches like the one you're experiencing right now.

Grant Limberg
A: 

You need to configure project properties so that your debug build links with DCMTK's debug build and your release build links with DCMTK's release build.

The above is what you need to do. Below are explanations of some other random things you asked about.

Older versions of Visual Studio used to have single threaded libraries (release and debug versions) besides multithreaded libraries (release and debug versions). For your project you can pretend single threaded libraries never existed.

If you experiment with random ways to trick the linker into shutting up and leaving problems to be found by your customers instead of by yourself, you might find that the /NODEFAULTLIB option will do that. The makers of the DCMTK library are warning you not to do that because some other people did the same dumb thing in the past.

Windows programmer
+2  A: 

Whats up with the "Debug Mode" (Multi-Threaded Debug) and "Release Mode" (Multi-Threaded)? What exactly is happening under the hood? Why exactly this thing is causing linking error?

The linker drags in libraries for several different reasons. The simplest is that a library is listed on the linker command line, or in the linker answer file on the linker command line. But any object files, whether compiled in your project or packed into a library, can also contain linker options including requesting particular libraries be linked in. In fact, the Visual C++ compiler automatically embeds such linker options matching the project options you use when compiling.

At link time, all the linker options from all object files and objects in static library files get combined. If more than one CRT library filename is requested, the linker reads in all of them and them you get naming conflicts, where the linker doesn't know which one to use.

I wonder if there is something called "Single-Threaded Debug" and "Single-Threaded" which again causes the same thing.

There used to be, but the last few versions of Visual C++ have only shipped multi-thread compatible libraries.

Documentation talks something about "Code Generation Options". What Code Generation Options? WTH are they?

Look inside your project options.

Documentation specifically warns us not to use /NODEFAULTLIB workaround. (example /NODEFAULTLIB :msvcrt ). Why? How would I cause troubles? what exactly is it?

If you use /NODEFAULTLIB, all the linker settings stored within object files and objects in libraries get ignored. You'll end up with no runtime library and maybe missing other libraries. You can add them back in by hand, but it's still a big mess.

Please explain the last point in the documentation for MFC users. Because I'm going to use MFC later in this project. Explain Why should we do it? What troubles would it cause if I don't. Anything more you'd like to mention? I mean regarding similar errors. I'm very interested in Linker & its problems. So, if there are any similar things you can mentions them or some keywords atleast.

MFC applications and the MFC library have to use the same memory management functions, so that memory allocated by MFC can be freed by the application and vice-versa. FILE handles and other resources are also shared. The MFC DLLs are already compiled to use the CRT in a DLL, and in order to be able to share resources you need to use the same CRT, which means using a DLL too.

Ben Voigt