Skip to content

Commit 544048c

Browse files
committed
[clang][MinGW] Implement -mcrtdll option to swtich crt choice
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 llvm#149434
1 parent e3dd50c commit 544048c

File tree

9 files changed

+162
-13
lines changed

9 files changed

+162
-13
lines changed

clang/include/clang/Basic/DiagnosticFrontendKinds.td

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -393,6 +393,9 @@ def warn_hlsl_langstd_minimal :
393393
"recommend using %1 instead">,
394394
InGroup<HLSLDXCCompat>;
395395

396+
def err_unknown_crtdll : Error<"unknown Windows/MinGW C runtime library '%0'">,
397+
DefaultFatal;
398+
396399
// ClangIR frontend errors
397400
def err_cir_to_cir_transform_failed : Error<
398401
"CIR-to-CIR transformation failed">, DefaultFatal;

clang/include/clang/Basic/LangOptions.def

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -493,6 +493,9 @@ LANGOPT(BoundsSafety, 1, 0, NotCompatible, "Bounds safety extension for C")
493493

494494
LANGOPT(PreserveVec3Type, 1, 0, NotCompatible, "Preserve 3-component vector type")
495495

496+
ENUM_LANGOPT(MinGWCRTDll, WindowsCRTDLLVersion, 4, WindowsCRTDLLVersion::CRTDLL_Default, NotCompatible,
497+
"MinGW specific. Controls the __MSVCRT_VERSION and related preprocessor defines.")
498+
496499
#undef LANGOPT
497500
#undef ENUM_LANGOPT
498501
#undef VALUE_LANGOPT

clang/include/clang/Basic/LangOptions.h

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -164,6 +164,23 @@ class LangOptionsBase {
164164
MSVC2022_9 = 1939,
165165
};
166166

167+
enum WindowsCRTDLLVersion {
168+
CRTDLL_Default,
169+
CRTDLL,
170+
MSVCRT10,
171+
MSVCRT20,
172+
MSVCRT40,
173+
MSVCRTD,
174+
MSVCR70,
175+
MSVCR71,
176+
MSVCR80,
177+
MSVCR90,
178+
MSVCR100,
179+
MSVCR110,
180+
MSVCR120,
181+
UCRT
182+
};
183+
167184
enum SYCLMajorVersion {
168185
SYCL_None,
169186
SYCL_2017,

clang/include/clang/Driver/Options.td

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1625,6 +1625,12 @@ defm auto_import : BoolFOption<"auto-import",
16251625
PosFlag<SetTrue, [], [], "MinGW specific. Enable code generation support for "
16261626
"automatic dllimport, and enable support for it in the linker. "
16271627
"Enabled by default.">>;
1628+
def mcrtdll_EQ : Joined<["-"], "mcrtdll=">,
1629+
Group<m_Group>,
1630+
Visibility<[ClangOption, CC1Option]>,
1631+
HelpText<"MinGW specific. Changes preprocessor flags and "
1632+
"linker options to use the"
1633+
"specified C runtime library.">;
16281634
} // let Flags = [TargetSpecific]
16291635

16301636
// In the future this option will be supported by other offloading

clang/lib/Basic/Targets/OSTargets.cpp

Lines changed: 47 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -141,8 +141,54 @@ static void addMinGWDefines(const llvm::Triple &Triple, const LangOptions &Opts,
141141
DefineStd(Builder, "WIN64", Opts);
142142
Builder.defineMacro("__MINGW64__");
143143
}
144-
Builder.defineMacro("__MSVCRT__");
145144
Builder.defineMacro("__MINGW32__");
145+
if (Opts.getMinGWCRTDll() == LangOptions::WindowsCRTDLLVersion::CRTDLL) {
146+
Builder.defineMacro("__CRTDLL__");
147+
} else {
148+
Builder.defineMacro("__MSVCRT__");
149+
switch (Opts.getMinGWCRTDll()) {
150+
case LangOptions::WindowsCRTDLLVersion::CRTDLL_Default:
151+
break;
152+
case LangOptions::WindowsCRTDLLVersion::MSVCRT10:
153+
Builder.defineMacro("__MSVCRT_VERSION__", "0x100");
154+
break;
155+
case LangOptions::WindowsCRTDLLVersion::MSVCRT20:
156+
Builder.defineMacro("__MSVCRT_VERSION__", "0x200");
157+
break;
158+
case LangOptions::WindowsCRTDLLVersion::MSVCRT40:
159+
Builder.defineMacro("__MSVCRT_VERSION__", "0x400");
160+
break;
161+
case LangOptions::WindowsCRTDLLVersion::MSVCRTD:
162+
Builder.defineMacro("__MSVCRT_VERSION__", "0x600");
163+
break;
164+
case LangOptions::WindowsCRTDLLVersion::MSVCR70:
165+
Builder.defineMacro("__MSVCRT_VERSION__", "0x700");
166+
break;
167+
case LangOptions::WindowsCRTDLLVersion::MSVCR71:
168+
Builder.defineMacro("__MSVCRT_VERSION__", "0x701");
169+
break;
170+
case LangOptions::WindowsCRTDLLVersion::MSVCR80:
171+
Builder.defineMacro("__MSVCRT_VERSION__", "0x800");
172+
break;
173+
case LangOptions::WindowsCRTDLLVersion::MSVCR90:
174+
Builder.defineMacro("__MSVCRT_VERSION__", "0x900");
175+
break;
176+
case LangOptions::WindowsCRTDLLVersion::MSVCR100:
177+
Builder.defineMacro("__MSVCRT_VERSION__", "0xA00");
178+
break;
179+
case LangOptions::WindowsCRTDLLVersion::MSVCR110:
180+
Builder.defineMacro("__MSVCRT_VERSION__", "0xB00");
181+
break;
182+
case LangOptions::WindowsCRTDLLVersion::MSVCR120:
183+
Builder.defineMacro("__MSVCRT_VERSION__", "0xC00");
184+
break;
185+
case LangOptions::WindowsCRTDLLVersion::UCRT:
186+
Builder.defineMacro("_UCRT");
187+
break;
188+
default:
189+
llvm_unreachable("Unknown MinGW CRT version");
190+
}
191+
}
146192
addCygMingDefines(Opts, Builder);
147193
}
148194

clang/lib/Driver/ToolChains/Clang.cpp

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5970,6 +5970,7 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA,
59705970
if (Triple.isWindowsGNUEnvironment()) {
59715971
Args.addOptOutFlag(CmdArgs, options::OPT_fauto_import,
59725972
options::OPT_fno_auto_import);
5973+
Args.addLastArg(CmdArgs, options::OPT_mcrtdll_EQ);
59735974
}
59745975

59755976
if (Args.hasFlag(options::OPT_fms_volatile, options::OPT_fno_ms_volatile,

clang/lib/Driver/ToolChains/MinGW.cpp

Lines changed: 17 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -85,19 +85,24 @@ void tools::MinGW::Linker::AddLibGCC(const ArgList &Args,
8585

8686
CmdArgs.push_back("-lmoldname");
8787
CmdArgs.push_back("-lmingwex");
88-
for (auto Lib : Args.getAllArgValues(options::OPT_l)) {
89-
if (StringRef(Lib).starts_with("msvcr") ||
90-
StringRef(Lib).starts_with("ucrt") ||
91-
StringRef(Lib).starts_with("crtdll")) {
92-
Lib = (llvm::Twine("-l") + Lib).str();
93-
// Respect the user's chosen crt variant, but still provide it
94-
// again as the last linker argument, because some of the libraries
95-
// we added above may depend on it.
96-
CmdArgs.push_back(Args.MakeArgStringRef(Lib));
97-
return;
98-
}
88+
89+
if (Arg *A = Args.getLastArg(options::OPT_mcrtdll_EQ)) {
90+
std::string mcrtdll = (Twine("-l") + A->getValue()).str();
91+
CmdArgs.push_back(Args.MakeArgStringRef(mcrtdll));
92+
} else {
93+
for (auto Lib : Args.getAllArgValues(options::OPT_l))
94+
if (StringRef(Lib).starts_with("msvcr") ||
95+
StringRef(Lib).starts_with("ucrt") ||
96+
StringRef(Lib).starts_with("crtdll")) {
97+
Lib = (llvm::Twine("-l") + Lib).str();
98+
// Respect the user's chosen crt variant, but still provide it
99+
// again as the last linker argument, because some of the libraries
100+
// we added above may depend on it.
101+
CmdArgs.push_back(Args.MakeArgStringRef(Lib));
102+
return;
103+
}
104+
CmdArgs.push_back("-lmsvcrt");
99105
}
100-
CmdArgs.push_back("-lmsvcrt");
101106
}
102107

103108
void tools::MinGW::Linker::ConstructJob(Compilation &C, const JobAction &JA,

clang/lib/Frontend/CompilerInvocation.cpp

Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4705,6 +4705,44 @@ bool CompilerInvocation::ParseLangArgs(LangOptions &Opts, ArgList &Args,
47054705
}
47064706
}
47074707

4708+
// Process MinGW -mcrtdll option
4709+
if (Arg *A = Args.getLastArg(OPT_mcrtdll_EQ)) {
4710+
Opts.MinGWCRTDll =
4711+
llvm::StringSwitch<enum LangOptions::WindowsCRTDLLVersion>(
4712+
A->getValue())
4713+
.StartsWithLower("crtdll",
4714+
LangOptions::WindowsCRTDLLVersion::CRTDLL)
4715+
.StartsWithLower("msvcrt10",
4716+
LangOptions::WindowsCRTDLLVersion::MSVCRT10)
4717+
.StartsWithLower("msvcrt20",
4718+
LangOptions::WindowsCRTDLLVersion::MSVCRT20)
4719+
.StartsWithLower("msvcrt40",
4720+
LangOptions::WindowsCRTDLLVersion::MSVCRT40)
4721+
.StartsWithLower("msvcr40",
4722+
LangOptions::WindowsCRTDLLVersion::MSVCRT40)
4723+
.StartsWithLower("msvcrtd",
4724+
LangOptions::WindowsCRTDLLVersion::MSVCRTD)
4725+
.StartsWithLower("msvcr70",
4726+
LangOptions::WindowsCRTDLLVersion::MSVCR70)
4727+
.StartsWithLower("msvcr71",
4728+
LangOptions::WindowsCRTDLLVersion::MSVCR71)
4729+
.StartsWithLower("msvcr80",
4730+
LangOptions::WindowsCRTDLLVersion::MSVCR80)
4731+
.StartsWithLower("msvcr90",
4732+
LangOptions::WindowsCRTDLLVersion::MSVCR90)
4733+
.StartsWithLower("msvcr100",
4734+
LangOptions::WindowsCRTDLLVersion::MSVCR100)
4735+
.StartsWithLower("msvcr110",
4736+
LangOptions::WindowsCRTDLLVersion::MSVCR110)
4737+
.StartsWithLower("msvcr120",
4738+
LangOptions::WindowsCRTDLLVersion::MSVCR120)
4739+
.StartsWithLower("ucrt", LangOptions::WindowsCRTDLLVersion::UCRT)
4740+
.Default(LangOptions::WindowsCRTDLLVersion::CRTDLL_Default);
4741+
if (Opts.MinGWCRTDll == LangOptions::WindowsCRTDLLVersion::CRTDLL_Default) {
4742+
Diags.Report(diag::err_unknown_crtdll) << A->getValue();
4743+
}
4744+
}
4745+
47084746
return Diags.getNumErrors() == NumErrorsBefore;
47094747
}
47104748

clang/test/Driver/mingw-mcrtdll.c

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
// RUN: %clang -v --target=x86_64-w64-mingw32 -### %s 2>&1 | FileCheck -check-prefix=DEFAULT %s
2+
// RUN: %clang -v --target=x86_64-w64-mingw32 -mcrtdll=msvcr90 -### %s 2>&1 | FileCheck -check-prefix=MSVCR90 %s
3+
// RUN: %clang -v --target=x86_64-w64-mingw32 -mcrtdll=msvcr90_suffix -### %s 2>&1 | FileCheck -check-prefix=MSVCR90_SUFFIX %s
4+
// RUN: %clang -v --target=x86_64-w64-mingw32 -mcrtdll=ucrt -### %s 2>&1 | FileCheck -check-prefix=UCRT %s
5+
// RUN: %clang -v --target=x86_64-w64-mingw32 -mcrtdll=ucrtbase -### %s 2>&1 | FileCheck -check-prefix=UCRTBASE %s
6+
7+
// RUN: %clang -dM -E --target=x86_64-w64-mingw32 %s 2>&1 | FileCheck -check-prefix=DEFINE_DEFAULT %s
8+
// RUN: %clang -dM -E --target=x86_64-w64-mingw32 -mcrtdll=msvcr90 %s 2>&1 | FileCheck -check-prefix=DEFINE_MSVCR90 %s
9+
// RUN: %clang -dM -E --target=x86_64-w64-mingw32 -mcrtdll=msvcr90_suffix %s 2>&1 | FileCheck -check-prefix=DEFINE_MSVCR90 %s
10+
// RUN: %clang -dM -E --target=x86_64-w64-mingw32 -mcrtdll=ucrt %s 2>&1 | FileCheck -check-prefix=DEFINE_UCRT %s
11+
// RUN: %clang -dM -E --target=x86_64-w64-mingw32 -mcrtdll=ucrtbase %s 2>&1 | FileCheck -check-prefix=DEFINE_UCRT %s
12+
// RUN: not %clang -dM -E --target=x86_64-w64-mingw32 -mcrtdll=bad %s 2>&1 | FileCheck -check-prefix=BAD %s
13+
14+
// DEFAULT: "-lmingwex" "-lmsvcrt"
15+
// DEFINE_DEFAULT: #define __MSVCRT__
16+
// MSVCR90: "-lmingwex" "-lmsvcr90"
17+
// DEFINE_MSVCR90: #define __MSVCRT_VERSION__ 0x900
18+
// DEFINE_MSVCR90: #define __MSVCRT__
19+
// MSVCR90-NOT: "-lmsvcrt"
20+
// MSVCR90_SUFFIX: "-lmingwex" "-lmsvcr90_suffix"
21+
// MSVCR90_SUFFIX-NOT: "-lmsvcrt"
22+
// UCRT: "-lmingwex" "-lucrt"
23+
// DEFINE_UCRT: #define _UCRT
24+
// DEFINE_UCRT-NOT: #define __MSVCRT_VERSION__
25+
// UCRT-NOT: "-lmsvcrt"
26+
// UCRTBASE: "-lmingwex" "-lucrtbase"
27+
// UCRTBASE-NOT: "-lmsvcrt"
28+
// DEFINE_CRTDLL: #define __CRTDLL__
29+
// DEFINE_CRTDLL-NOT: #define __MSVCRT__
30+
// BAD: error: unknown Windows/MinGW C runtime library 'bad'

0 commit comments

Comments
 (0)