In Visual Studio, I can compile my code using /MT or /MD [MSDN]. I think I don't understand all the implications that those options have.
My current understanding is:
new
in order to guarantee that multiple threads don't run into a data race when generating pointers". There may have been a single-thread version in the past./MD
is the dynamic "linking" and /MT
is the static "linking"./MD
will result in a smaller executable, but will load ucrtbase.dll
, which then loads the C runtime DLLs, e.g. VCRUNTIME140.dll
, VCRUNTIME140_1.dll
and MSVCP140.dll
(or their debug versions). I need a redistributable version of these when I create my installer (vcredist [MSDN])./MT
will result in a larger executable, but contains the C runtime directly, so that no additional DLLs need to be loaded./MD
is beneficial, since each individual DLL is smaller and the above mentioned DLLs are only loaded into the process once. So basically, I should compile at least all DLLs with /MD
./Mxd
of the C runtime use a different memory layout and e.g. use 0xCCCCCCCC as fill patterns to detect buffer overflows/underruns./MD
and MT
in a compilation step./MD
defines _DLL
and programs could do all sorts of #ifdef _DLL
magic, but probably they shouldn't. One such example is errno
which can be a simple extern int (for /MT) but a function call (for /MD)./MT
, each module gets its own CRT heap, so memory must be freed in the module it was allocated. (Source [MSDN] and [Source [MSDN]](Potential Errors Passing CRT Objects Across DLL Boundaries))Is above understanding correct? Did I miss an important point?
My aim is to understand (J). I want to make sure I understood the rest of the topic on my way there.
I have read
/MT and /MD don't relate to multi-threaded nature, but how the runtime is provided (as a statically linked library, or as a DLL).
Since Visual Studio 2005, that has been the case.
/MT provides a larger executable, with limited dependencies. /MD provides a smaller executable, but needs a DLL installed.
Using /MT for an installer makes sense. /MD can (depending on Visual Studio version get an automatically upgraded DLL when bugs are found.
(A) the "multi-threading" part which MSDN talks about has nothing to do with my application. My application can still be single-threaded. It's the C runtime which is capable of multi-threading. I understand that as "the C runtime uses synchronization around new in order to guarantee that multiple threads don't run into a data race when generating pointers". There may have been a single-thread version in the past.
Windows is inherently multi-threaded. Code such as errno is implemented these days as a variable in thread-local-storage, and has no synchronization cost. The heap is always (in modern Visual Studio) implemented by the Windows platform, and that is multi-threaded
(B) although these are compiler options, this is technically more like a linking thing. /MD is the dynamic "linking" and /MT is the static "linking".
These options change the mechanisms used by the runtime to deliver correct behavior. So they affect the compilation. Different code is needed to manage threads when the runtime is in a DLL, than when it is in the same binary. So the switches change both compile and the linker.
(C) /MD will result in a smaller executable, but will load ucrtbase.dll, which then loads the C runtime DLLs, e.g. VCRUNTIME140.dll, VCRUNTIME140_1.dll and MSVCP140.dll (or their debug versions). I need a redistributable version of these when I create my installer (vcredist [MSDN]).
That is correct
(D) /MT will result in a larger executable, but contains the C runtime directly, so that no additional DLLs need to be loaded.
At the limit that is correct, but some functionality can still be supplied by DLLs outside of the EXE. It should not require any unexpected DLLs to be shipped.
(E) if I have a large application (e.g. 5MLoC, 100 own DLLs), choosing /MD is beneficial, since each individual DLL is smaller and the above mentioned DLLs are only loaded into the process once. So basically, I should compile at least all DLLs with /MD.
There are lots of reasons to choose between DLL and statically linking.
(F) the debug versions /Mxd of the C runtime use a different memory layout and e.g. use 0xCCCCCCCC as fill patterns to detect buffer overflows/underruns. Note the debug DLL version of the runtime is not shippable, there is no license to deploy outside of your environment.
Significantly the debug runtime has more self-checking, ensuring that the code is following rules, means the code runs slower.
The stack and heap are initialized to "bad" values to detect uninitialized variables STL iterators may compare the source objects (breaking the O(x) rules for the containers).
(H) /MD defines _DLL and programs could do all sorts of #ifdef _DLL magic, but probably they shouldn't. One such example is errno which can be a simple extern int (for /MT) but a function call (for /MD).
_DLL is needed to ensure runtime understands how it can manage thread-local-storage. The DLL version can get Thread Initialization messages, and thus can use these to ensure thread data is managed correctly.
(J) with /MT, each module gets its own CRT heap, so memory must be freed in the module it was allocated. (Source [MSDN] and [Source [MSDN]](Potential Errors Passing CRT Objects Across DLL Boundaries))
All modern Visual C++ versions use a single process heap, and so that statement is somewhat stale. The pains of separate heaps (ensuring free
is called in same binary as malloc
was considered too high to make up for the ability to track down memory leaks to particular DLLs / EXE.