Search code examples
cvisual-c++linkerlinker-flagscl

Compiling C file with /c and /MD options, then linking .lib files


I have a C file which uses 3-4 external libraries. It's built using cl.exe and link.exe(MSVC).

The build script shows that the process of generating the exe is in two stages-

  • Use the '/c' option with cl.exe to get the .o file. A bunch of other flags are also given with this, but the one I'm concerned with is /MD. MSDN says:

Causes the application to use the multithread-specific and DLL-specific version of the run-time library. Defines _MT and _DLL and causes the compiler to place the library name MSVCRT.lib into the .obj file.

What is the use of giving /MD with cl when we are only compiling, and not linking ?

  • After this, link.exe is used to generate the exe. Several .lib files are specified for linking (like ole32.lib, advapi32.lib, user32.lib etc and other non-MSVC specific ones). My question is that aren't .lib files used for static linking ? If yes, then why is the final exe only about 500 KB ? None of the .libs are import libraries.

    If not, then does link use static or dynamic linking by default ? Does the /MD given with cl have any effect here ?


Solution

  • The original C runtime library was never envisioned to ever have to support programs that are built from multiple modules. It contains global variables, like errno and stdout and functions that have implicit global state, like strtok() and malloc(). You can link DLLs with their own copy of the CRT but that puts rather draconian requirements on how you design the DLL interface. You have to be very careful to never take a dependency on CRT state. Getting this wrong produces almost impossible to diagnose runtime misbehavior.

    A workaround for this is to only ever have one copy of the CRT in your process. Which is what /MD accomplishes, you'll end up taking a dependency on the version of the CRT that's stored in a DLL. Shared by all modules. Like msvcr120.dll, the one used by VS2013.

    The compiler needs to know this so it can properly use that DLL version. A simple example is errno, it is a global variable with /MT but is macro-ed to a function call with /MD so that only the one global inside the DLL is ever used to track the last known value. The _DLL macro will be defined if /MD is in effect, used in the compiler's .h files.

    One more side effect is that the compiler automatically inserts a link directive (equivalent to #pragma comment) for either msvcrt.lib or libcmt.lib. Designed to help you avoid mistakes and omit the needs to give the CRT library link instruction explicitly. Getting it wrong produces very hard to diagnose linker error messages. Not unlike the kind you get when you try to link .obj or .lib files that were built with a mismatch of /MT and /MD. Which of course cannot work properly, you can't have a dependency on both.

    None of the .libs are import libraries

    The ones you listed by name, ole32.lib, advapi32.lib, user32.lib, are in fact import libraries. They are standard operating system DLLs. At runtime, your program will load the corresponding DLLs, easily visible from a debugger. For VS you'll see this in the Output window. Noteworthy perhaps is that these DLLs do in fact use a different CRT than your program, they bind to c:\windows\system32\msvcrt.dll. The winapi was carefully designed to not ever make this an issue.

    does link use static or dynamic linking by default

    There is no default, it depends on the .lib you link. Distinguish between static link libraries and import libraries. An import library is created when you build a DLL. It is small file that contains no code, just the names of exported functions in the DLL so the linker knows to put an entry in the program's import table. The DLL dependency is resolved and the imported functions are bound by the loader when the program is started.