[clang] [clang][MinGW] Implement -mcrtdll option to switch crt choice (PR #149469)
via cfe-commits
cfe-commits at lists.llvm.org
Fri Jul 18 00:57:18 PDT 2025
llvmbot wrote:
<!--LLVM PR SUMMARY COMMENT-->
@llvm/pr-subscribers-clang-driver
Author: Keno Fischer (Keno)
<details>
<summary>Changes</summary>
This implements the mingw `-mcrtdll` option recently added to gcc.
This option is useful for having the compiler be in charge of crt
version selection while only shipping a single copy of mingw for a
multi-ABI toolchain. That said, there are various ABI dependent compiler
libraries (e.g. libstdc++), so a certain degree of ABI awareness is
nevertheless required in order to use this option correctly.
See also #<!-- -->149434 (which this branch includes, since it touches the same code).
---
Full diff: https://github.com/llvm/llvm-project/pull/149469.diff
10 Files Affected:
- (modified) clang/include/clang/Basic/DiagnosticFrontendKinds.td (+3)
- (modified) clang/include/clang/Basic/LangOptions.def (+3)
- (modified) clang/include/clang/Basic/LangOptions.h (+17)
- (modified) clang/include/clang/Driver/Options.td (+6)
- (modified) clang/lib/Basic/Targets/OSTargets.cpp (+47-1)
- (modified) clang/lib/Driver/ToolChains/Clang.cpp (+1)
- (modified) clang/lib/Driver/ToolChains/MinGW.cpp (+18-6)
- (modified) clang/lib/Frontend/CompilerInvocation.cpp (+38)
- (added) clang/test/Driver/mingw-mcrtdll.c (+30)
- (modified) clang/test/Driver/mingw-msvcrt.c (+4-4)
``````````diff
diff --git a/clang/include/clang/Basic/DiagnosticFrontendKinds.td b/clang/include/clang/Basic/DiagnosticFrontendKinds.td
index 8a8db27490f06..3de97a0ec3955 100644
--- a/clang/include/clang/Basic/DiagnosticFrontendKinds.td
+++ b/clang/include/clang/Basic/DiagnosticFrontendKinds.td
@@ -393,6 +393,9 @@ def warn_hlsl_langstd_minimal :
"recommend using %1 instead">,
InGroup<HLSLDXCCompat>;
+def err_unknown_crtdll : Error<"unknown Windows/MinGW C runtime library '%0'">,
+ DefaultFatal;
+
// ClangIR frontend errors
def err_cir_to_cir_transform_failed : Error<
"CIR-to-CIR transformation failed">, DefaultFatal;
diff --git a/clang/include/clang/Basic/LangOptions.def b/clang/include/clang/Basic/LangOptions.def
index e43238ba683f2..46f03982a041b 100644
--- a/clang/include/clang/Basic/LangOptions.def
+++ b/clang/include/clang/Basic/LangOptions.def
@@ -493,6 +493,9 @@ LANGOPT(BoundsSafety, 1, 0, NotCompatible, "Bounds safety extension for C")
LANGOPT(PreserveVec3Type, 1, 0, NotCompatible, "Preserve 3-component vector type")
+ENUM_LANGOPT(MinGWCRTDll, WindowsCRTDLLVersion, 4, WindowsCRTDLLVersion::CRTDLL_Default, NotCompatible,
+ "MinGW specific. Controls the __MSVCRT_VERSION and related preprocessor defines.")
+
#undef LANGOPT
#undef ENUM_LANGOPT
#undef VALUE_LANGOPT
diff --git a/clang/include/clang/Basic/LangOptions.h b/clang/include/clang/Basic/LangOptions.h
index 4c642c9e10c91..a0160017b6813 100644
--- a/clang/include/clang/Basic/LangOptions.h
+++ b/clang/include/clang/Basic/LangOptions.h
@@ -164,6 +164,23 @@ class LangOptionsBase {
MSVC2022_9 = 1939,
};
+ enum WindowsCRTDLLVersion {
+ CRTDLL_Default,
+ CRTDLL,
+ MSVCRT10,
+ MSVCRT20,
+ MSVCRT40,
+ MSVCRTD,
+ MSVCR70,
+ MSVCR71,
+ MSVCR80,
+ MSVCR90,
+ MSVCR100,
+ MSVCR110,
+ MSVCR120,
+ UCRT
+ };
+
enum SYCLMajorVersion {
SYCL_None,
SYCL_2017,
diff --git a/clang/include/clang/Driver/Options.td b/clang/include/clang/Driver/Options.td
index d0b54a446309b..6ad978c525812 100644
--- a/clang/include/clang/Driver/Options.td
+++ b/clang/include/clang/Driver/Options.td
@@ -1625,6 +1625,12 @@ defm auto_import : BoolFOption<"auto-import",
PosFlag<SetTrue, [], [], "MinGW specific. Enable code generation support for "
"automatic dllimport, and enable support for it in the linker. "
"Enabled by default.">>;
+def mcrtdll_EQ : Joined<["-"], "mcrtdll=">,
+ Group<m_Group>,
+ Visibility<[ClangOption, CC1Option]>,
+ HelpText<"MinGW specific. Changes preprocessor flags and "
+ "linker options to use the"
+ "specified C runtime library.">;
} // let Flags = [TargetSpecific]
// In the future this option will be supported by other offloading
diff --git a/clang/lib/Basic/Targets/OSTargets.cpp b/clang/lib/Basic/Targets/OSTargets.cpp
index e744e84a5b079..8e48228d1220f 100644
--- a/clang/lib/Basic/Targets/OSTargets.cpp
+++ b/clang/lib/Basic/Targets/OSTargets.cpp
@@ -141,8 +141,54 @@ static void addMinGWDefines(const llvm::Triple &Triple, const LangOptions &Opts,
DefineStd(Builder, "WIN64", Opts);
Builder.defineMacro("__MINGW64__");
}
- Builder.defineMacro("__MSVCRT__");
Builder.defineMacro("__MINGW32__");
+ if (Opts.getMinGWCRTDll() == LangOptions::WindowsCRTDLLVersion::CRTDLL) {
+ Builder.defineMacro("__CRTDLL__");
+ } else {
+ Builder.defineMacro("__MSVCRT__");
+ switch (Opts.getMinGWCRTDll()) {
+ case LangOptions::WindowsCRTDLLVersion::CRTDLL_Default:
+ break;
+ case LangOptions::WindowsCRTDLLVersion::MSVCRT10:
+ Builder.defineMacro("__MSVCRT_VERSION__", "0x100");
+ break;
+ case LangOptions::WindowsCRTDLLVersion::MSVCRT20:
+ Builder.defineMacro("__MSVCRT_VERSION__", "0x200");
+ break;
+ case LangOptions::WindowsCRTDLLVersion::MSVCRT40:
+ Builder.defineMacro("__MSVCRT_VERSION__", "0x400");
+ break;
+ case LangOptions::WindowsCRTDLLVersion::MSVCRTD:
+ Builder.defineMacro("__MSVCRT_VERSION__", "0x600");
+ break;
+ case LangOptions::WindowsCRTDLLVersion::MSVCR70:
+ Builder.defineMacro("__MSVCRT_VERSION__", "0x700");
+ break;
+ case LangOptions::WindowsCRTDLLVersion::MSVCR71:
+ Builder.defineMacro("__MSVCRT_VERSION__", "0x701");
+ break;
+ case LangOptions::WindowsCRTDLLVersion::MSVCR80:
+ Builder.defineMacro("__MSVCRT_VERSION__", "0x800");
+ break;
+ case LangOptions::WindowsCRTDLLVersion::MSVCR90:
+ Builder.defineMacro("__MSVCRT_VERSION__", "0x900");
+ break;
+ case LangOptions::WindowsCRTDLLVersion::MSVCR100:
+ Builder.defineMacro("__MSVCRT_VERSION__", "0xA00");
+ break;
+ case LangOptions::WindowsCRTDLLVersion::MSVCR110:
+ Builder.defineMacro("__MSVCRT_VERSION__", "0xB00");
+ break;
+ case LangOptions::WindowsCRTDLLVersion::MSVCR120:
+ Builder.defineMacro("__MSVCRT_VERSION__", "0xC00");
+ break;
+ case LangOptions::WindowsCRTDLLVersion::UCRT:
+ Builder.defineMacro("_UCRT");
+ break;
+ default:
+ llvm_unreachable("Unknown MinGW CRT version");
+ }
+ }
addCygMingDefines(Opts, Builder);
}
diff --git a/clang/lib/Driver/ToolChains/Clang.cpp b/clang/lib/Driver/ToolChains/Clang.cpp
index fe1865888bdd0..79344f4e760d9 100644
--- a/clang/lib/Driver/ToolChains/Clang.cpp
+++ b/clang/lib/Driver/ToolChains/Clang.cpp
@@ -5970,6 +5970,7 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA,
if (Triple.isWindowsGNUEnvironment()) {
Args.addOptOutFlag(CmdArgs, options::OPT_fauto_import,
options::OPT_fno_auto_import);
+ Args.addLastArg(CmdArgs, options::OPT_mcrtdll_EQ);
}
if (Args.hasFlag(options::OPT_fms_volatile, options::OPT_fno_ms_volatile,
diff --git a/clang/lib/Driver/ToolChains/MinGW.cpp b/clang/lib/Driver/ToolChains/MinGW.cpp
index 7d093d20b3dd9..7223cda83fa70 100644
--- a/clang/lib/Driver/ToolChains/MinGW.cpp
+++ b/clang/lib/Driver/ToolChains/MinGW.cpp
@@ -85,12 +85,24 @@ void tools::MinGW::Linker::AddLibGCC(const ArgList &Args,
CmdArgs.push_back("-lmoldname");
CmdArgs.push_back("-lmingwex");
- for (auto Lib : Args.getAllArgValues(options::OPT_l))
- if (StringRef(Lib).starts_with("msvcr") ||
- StringRef(Lib).starts_with("ucrt") ||
- StringRef(Lib).starts_with("crtdll"))
- return;
- CmdArgs.push_back("-lmsvcrt");
+
+ if (Arg *A = Args.getLastArg(options::OPT_mcrtdll_EQ)) {
+ std::string mcrtdll = (Twine("-l") + A->getValue()).str();
+ CmdArgs.push_back(Args.MakeArgStringRef(mcrtdll));
+ } else {
+ for (auto Lib : Args.getAllArgValues(options::OPT_l))
+ if (StringRef(Lib).starts_with("msvcr") ||
+ StringRef(Lib).starts_with("ucrt") ||
+ StringRef(Lib).starts_with("crtdll")) {
+ Lib = (llvm::Twine("-l") + Lib).str();
+ // Respect the user's chosen crt variant, but still provide it
+ // again as the last linker argument, because some of the libraries
+ // we added above may depend on it.
+ CmdArgs.push_back(Args.MakeArgStringRef(Lib));
+ return;
+ }
+ CmdArgs.push_back("-lmsvcrt");
+ }
}
void tools::MinGW::Linker::ConstructJob(Compilation &C, const JobAction &JA,
diff --git a/clang/lib/Frontend/CompilerInvocation.cpp b/clang/lib/Frontend/CompilerInvocation.cpp
index b9f75796ecc16..26d05bc419ccb 100644
--- a/clang/lib/Frontend/CompilerInvocation.cpp
+++ b/clang/lib/Frontend/CompilerInvocation.cpp
@@ -4705,6 +4705,44 @@ bool CompilerInvocation::ParseLangArgs(LangOptions &Opts, ArgList &Args,
}
}
+ // Process MinGW -mcrtdll option
+ if (Arg *A = Args.getLastArg(OPT_mcrtdll_EQ)) {
+ Opts.MinGWCRTDll =
+ llvm::StringSwitch<enum LangOptions::WindowsCRTDLLVersion>(
+ A->getValue())
+ .StartsWithLower("crtdll",
+ LangOptions::WindowsCRTDLLVersion::CRTDLL)
+ .StartsWithLower("msvcrt10",
+ LangOptions::WindowsCRTDLLVersion::MSVCRT10)
+ .StartsWithLower("msvcrt20",
+ LangOptions::WindowsCRTDLLVersion::MSVCRT20)
+ .StartsWithLower("msvcrt40",
+ LangOptions::WindowsCRTDLLVersion::MSVCRT40)
+ .StartsWithLower("msvcr40",
+ LangOptions::WindowsCRTDLLVersion::MSVCRT40)
+ .StartsWithLower("msvcrtd",
+ LangOptions::WindowsCRTDLLVersion::MSVCRTD)
+ .StartsWithLower("msvcr70",
+ LangOptions::WindowsCRTDLLVersion::MSVCR70)
+ .StartsWithLower("msvcr71",
+ LangOptions::WindowsCRTDLLVersion::MSVCR71)
+ .StartsWithLower("msvcr80",
+ LangOptions::WindowsCRTDLLVersion::MSVCR80)
+ .StartsWithLower("msvcr90",
+ LangOptions::WindowsCRTDLLVersion::MSVCR90)
+ .StartsWithLower("msvcr100",
+ LangOptions::WindowsCRTDLLVersion::MSVCR100)
+ .StartsWithLower("msvcr110",
+ LangOptions::WindowsCRTDLLVersion::MSVCR110)
+ .StartsWithLower("msvcr120",
+ LangOptions::WindowsCRTDLLVersion::MSVCR120)
+ .StartsWithLower("ucrt", LangOptions::WindowsCRTDLLVersion::UCRT)
+ .Default(LangOptions::WindowsCRTDLLVersion::CRTDLL_Default);
+ if (Opts.MinGWCRTDll == LangOptions::WindowsCRTDLLVersion::CRTDLL_Default) {
+ Diags.Report(diag::err_unknown_crtdll) << A->getValue();
+ }
+ }
+
return Diags.getNumErrors() == NumErrorsBefore;
}
diff --git a/clang/test/Driver/mingw-mcrtdll.c b/clang/test/Driver/mingw-mcrtdll.c
new file mode 100644
index 0000000000000..4558628766169
--- /dev/null
+++ b/clang/test/Driver/mingw-mcrtdll.c
@@ -0,0 +1,30 @@
+// RUN: %clang -v --target=x86_64-w64-mingw32 -### %s 2>&1 | FileCheck -check-prefix=DEFAULT %s
+// RUN: %clang -v --target=x86_64-w64-mingw32 -mcrtdll=msvcr90 -### %s 2>&1 | FileCheck -check-prefix=MSVCR90 %s
+// RUN: %clang -v --target=x86_64-w64-mingw32 -mcrtdll=msvcr90_suffix -### %s 2>&1 | FileCheck -check-prefix=MSVCR90_SUFFIX %s
+// RUN: %clang -v --target=x86_64-w64-mingw32 -mcrtdll=ucrt -### %s 2>&1 | FileCheck -check-prefix=UCRT %s
+// RUN: %clang -v --target=x86_64-w64-mingw32 -mcrtdll=ucrtbase -### %s 2>&1 | FileCheck -check-prefix=UCRTBASE %s
+
+// RUN: %clang -dM -E --target=x86_64-w64-mingw32 %s 2>&1 | FileCheck -check-prefix=DEFINE_DEFAULT %s
+// RUN: %clang -dM -E --target=x86_64-w64-mingw32 -mcrtdll=msvcr90 %s 2>&1 | FileCheck -check-prefix=DEFINE_MSVCR90 %s
+// RUN: %clang -dM -E --target=x86_64-w64-mingw32 -mcrtdll=msvcr90_suffix %s 2>&1 | FileCheck -check-prefix=DEFINE_MSVCR90 %s
+// RUN: %clang -dM -E --target=x86_64-w64-mingw32 -mcrtdll=ucrt %s 2>&1 | FileCheck -check-prefix=DEFINE_UCRT %s
+// RUN: %clang -dM -E --target=x86_64-w64-mingw32 -mcrtdll=ucrtbase %s 2>&1 | FileCheck -check-prefix=DEFINE_UCRT %s
+// RUN: not %clang -dM -E --target=x86_64-w64-mingw32 -mcrtdll=bad %s 2>&1 | FileCheck -check-prefix=BAD %s
+
+// DEFAULT: "-lmingwex" "-lmsvcrt"
+// DEFINE_DEFAULT: #define __MSVCRT__
+// MSVCR90: "-lmingwex" "-lmsvcr90"
+// DEFINE_MSVCR90: #define __MSVCRT_VERSION__ 0x900
+// DEFINE_MSVCR90: #define __MSVCRT__
+// MSVCR90-NOT: "-lmsvcrt"
+// MSVCR90_SUFFIX: "-lmingwex" "-lmsvcr90_suffix"
+// MSVCR90_SUFFIX-NOT: "-lmsvcrt"
+// UCRT: "-lmingwex" "-lucrt"
+// DEFINE_UCRT: #define _UCRT
+// DEFINE_UCRT-NOT: #define __MSVCRT_VERSION__
+// UCRT-NOT: "-lmsvcrt"
+// UCRTBASE: "-lmingwex" "-lucrtbase"
+// UCRTBASE-NOT: "-lmsvcrt"
+// DEFINE_CRTDLL: #define __CRTDLL__
+// DEFINE_CRTDLL-NOT: #define __MSVCRT__
+// BAD: error: unknown Windows/MinGW C runtime library 'bad'
diff --git a/clang/test/Driver/mingw-msvcrt.c b/clang/test/Driver/mingw-msvcrt.c
index 340ce1f57b0f8..e1648630476a0 100644
--- a/clang/test/Driver/mingw-msvcrt.c
+++ b/clang/test/Driver/mingw-msvcrt.c
@@ -7,10 +7,10 @@
// CHECK_DEFAULT: "-lmingwex" "-lmsvcrt" "-ladvapi32"
// CHECK_DEFAULT-SAME: "-lmsvcrt" "-lkernel32" "{{.*}}crtend.o"
// CHECK_MSVCR120: "-lmsvcr120"
-// CHECK_MSVCR120-SAME: "-lmingwex" "-ladvapi32"
+// CHECK_MSVCR120-SAME: "-lmingwex" "-lmsvcr120" "-ladvapi32"
// CHECK_UCRTBASE: "-lucrtbase"
-// CHECK_UCRTBASE-SAME: "-lmingwex" "-ladvapi32"
+// CHECK_UCRTBASE-SAME: "-lmingwex" "-lucrtbase" "-ladvapi32"
// CHECK_UCRT: "-lucrt"
-// CHECK_UCRT-SAME: "-lmingwex" "-ladvapi32"
+// CHECK_UCRT-SAME: "-lmingwex" "-lucrt" "-ladvapi32"
// CHECK_CRTDLL: "-lcrtdll"
-// CHECK_CRTDLL-SAME: "-lmingwex" "-ladvapi32"
+// CHECK_CRTDLL-SAME: "-lmingwex" "-lcrtdll" "-ladvapi32"
``````````
</details>
https://github.com/llvm/llvm-project/pull/149469
More information about the cfe-commits
mailing list