Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
22 changes: 22 additions & 0 deletions changelog/dmd.ucrt-runtime.dd
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
UCRT is now used for the C runtime on Windows

DMD on Windows now uses the Universal CRT (UCRT) for its C runtime in all cases.

For installations with Visual Studio 2015 (or later) or the Windows 10 SDK, the default
C runtime is unchanged: it remains $(TT libcmt), which statically links the UCRT.

When no such Visual C installation is found, DMD now falls back on the UCRT-based
libraries bundled in the MinGW folder shipped with DMD ($(TT ucrtbase.lib) together with
$(TT vcruntime140.lib)), instead of the old $(TT msvcrt120) runtime which did not support
modern format specifiers such as `%zd`. This fallback is fully supported.

If no UCRT-capable toolchain is detected and no $(TT -mscrtlib) switch is given, DMD now
reports a clear error instead of silently producing a non-working link.

Detection of Visual Studio versions older than 2015 (2008 - 2013) is deprecated, because
those versions predate the UCRT. Falling back on such an installation emits a deprecation
warning.

The $(TT -mscrtlib) switch is unchanged and can still be used to select any C runtime,
including $(TT msvcrt) (dynamic), the debug variants $(TT libcmtd) / $(TT msvcrtd), or a
legacy $(TT msvcrtNNN) runtime.
14 changes: 7 additions & 7 deletions compiler/src/dmd/cli.d
Original file line number Diff line number Diff line change
Expand Up @@ -725,13 +725,13 @@ dmd -cov -unittest myprog.d
"If building MS-COFF object files when targeting Windows, embed a reference to
the given C runtime library $(I libname) into the object file containing `main`,
`DllMain` or `WinMain` for automatic linking. The default is $(TT libcmt)
(release version with static linkage), the other usual alternatives are
$(TT libcmtd), $(TT msvcrt) and $(TT msvcrtd).
If no Visual C installation is detected, a wrapper for the redistributable
VC2010 dynamic runtime library and mingw based platform import libraries will
be linked instead using the LLD linker provided by the LLVM project.
The detection can be skipped explicitly if $(TT msvcrt120) is specified as
$(I libname).
(release version with static linkage), which uses the Universal CRT (UCRT)
shipped with Visual Studio 2015 (or later) and the Windows 10 SDK. The other
usual alternatives are $(TT libcmtd), $(TT msvcrt) and $(TT msvcrtd).
If no Universal CRT capable Visual C installation is detected, the UCRT-based
libraries bundled with DMD (the mingw $(TT ucrtbase.lib) and
$(TT vcruntime140.lib)) are linked instead using the LLD linker provided by the
LLVM project.
If $(I libname) is empty, no C runtime library is automatically linked in.",
TargetOS.Windows,
),
Expand Down
20 changes: 14 additions & 6 deletions compiler/src/dmd/link.d
Original file line number Diff line number Diff line change
Expand Up @@ -286,9 +286,13 @@ public int runLINK(bool verbose, ErrorSink eSink)
}

VSOptions vsopt;
// if a runtime library (msvcrtNNN.lib) from the mingw folder is selected explicitly, do not detect VS and use lld
if (driverParams.mscrtlib.length <= 6 ||
driverParams.mscrtlib[0..6] != "msvcrt" || !isdigit(driverParams.mscrtlib[6]))
// If a MinGW-folder runtime is selected — the UCRT-based `ucrtbase`, or a
// legacy `msvcrtNNN` such as `msvcrt120` — do not detect Visual Studio; use
// lld-link with the MinGW libraries instead.
const isMingwRuntime = driverParams.mscrtlib == "ucrtbase" ||
(driverParams.mscrtlib.length > 6 &&
driverParams.mscrtlib[0 .. 6] == "msvcrt" && isdigit(driverParams.mscrtlib[6]));
if (!isMingwRuntime)
vsopt.initialize();

const(char)* linkcmd = getenv(target.isX86_64 ? "LINKCMD64" : "LINKCMD");
Expand All @@ -301,11 +305,15 @@ public int runLINK(bool verbose, ErrorSink eSink)
{
// object files not SAFESEH compliant, but LLD is more picky than MS link
cmdbuf.writestring(" /SAFESEH:NO");
// if we are using LLD as a fallback, don't link to any VS libs even if
// we detected a VS installation and they are present
vsopt.uninitialize();
// lld-link is used here as a generic linker fallback; keep any detected
// VS/UCRT library paths so the Universal CRT can still be linked.
}

// The UCRT-based MinGW fallback runtime links ucrtbase.lib via the object file's
// /DEFAULTLIB directive; it also needs the VC runtime library.
if (driverParams.mscrtlib == "ucrtbase")
cmdbuf.writestring(" vcruntime140.lib");

if (const(char)* lflags = vsopt.linkOptions(target.isX86_64))
{
cmdbuf.writeByte(' ');
Expand Down
18 changes: 17 additions & 1 deletion compiler/src/dmd/main.d
Original file line number Diff line number Diff line change
Expand Up @@ -1194,7 +1194,23 @@ void reconcileLinkRunLib(ref Param params, size_t numSrcFiles, const char[] obj_
{
VSOptions vsopt;
vsopt.initialize();
driverParams.mscrtlib = vsopt.defaultRuntimeLibrary(target.isX86_64).toDString;
if (const rtlib = vsopt.defaultRuntimeLibrary(target.isX86_64))
driverParams.mscrtlib = rtlib.toDString;
else
{
// No UCRT-capable Visual C installation (VS2015+ or the Windows SDK
// with the Universal CRT) and no MinGW fallback libraries were found.
if (driverParams.link)
eSink.error(Loc.initial, "no compatible C runtime found; install Visual Studio 2015 or later, or the Windows SDK with the Universal CRT, or specify the runtime with `-mscrtlib`");
// still embed a name in the object file so it can be linked elsewhere
driverParams.mscrtlib = "libcmt";
}

// @@@ Deprecated v2.117
// Deprecated in 2.113
// Remove this when the feature is removed from the language
if (vsopt.usedDeprecatedVSVersion)
eSink.deprecation(Loc.initial, "Visual Studio versions prior to 2015 are deprecated because they lack the Universal CRT (UCRT); install Visual Studio 2015 or later");
Comment thread
thewilsonator marked this conversation as resolved.
}
else
{
Expand Down
Loading
Loading