As the Windows port gets more stable, one thing which starts to stand out is the lack of support for proper linkage to MSVCRT. I would like to solicit some advice on how to best expose this in the swift driver.
The first issue is that there is a confusing landscape to cover. When I say MSVCRT (Microsoft Visual C Runtime) I really just mean the C runtime. There is the "deprecated" MSVCRT and the new more modern "ucrt". However, there is really no point in differentiating this as the ucrt is available in all partitions of Windows and in both the WIn32 mode as well as the Metro mode. So for the sake of this discussion, msvcrt and ucrt are synonymous as we will always use ucrt.
Now, the problem is that the runtime is available in 4 variants, each of which is ABI incompatible. So you must select one variant and be consistent throughout for it (the Swift runtime/standard library, libdispatch, Foundation, and application code). Failure to do so will result in runtime failures which are difficult to diagnose (as expected). Note that when performing a static link, ALL libraries must be statically linked into the final binary, including the standard library, any dependencies, and the C runtime as you may only have a single instance of the runtime otherwise you will have cross-domain frees and you will have mismatched resource tables (e.g. file descriptors).
The selection of the runtime in the C/C++ land is driven by a set of flags:
/MTd
/MT
/MDd
/MD
This is due to the programming model compatibility with the pre-multithreaded model. /MT
enables the multithreaded model with static linking, and /MTd
enables the multithreaded model with static linking with additional debugging features. /MD
is similar just with shared linkage (DLL mode). Note that the debug mode builds are not meant for distribution (there is no debug variant redistributable of the runtime). These flags enable a different set of C preprocessors.
Library | Associated DLL | Option | Preprocessor Directives | Distributable
--------------+----------------+--------+-------------------------+--------------
libucrt.lib | [static] | /MT | _MT | Y
libucrtd.lib | [static] | /MTd | _MT _DEBUG | N
ucrt.lib | ucrt.dll | /MD | _MT _DLL | Y
ucrtd.lib | ucrtd.dll | /MDd | _MT _DLL _DEBUG | N
Now, when the options are actually enabled in C/C++ code, the compiler will embed an appropriate directive for the linker to select the correct library and prevent the alternates from being pulled in. Since we do not do this in Swift currently, the user must correctly select the library to link against.
The question now is, is it acceptable to expose this control to the user? If so, what is the desired way to expose this to the user? At least for Windows developers, the /MT
, /MTd
, /MD
, /MDd
options are familiar. However, we also currently do not support /MT
or /MTd
configurations in the build (as I believe /MD
and /MDd
to be better and thus only bothered wiring that through).