Skip to content

[clang][MinGW] Implement -mcrtdll option to switch crt choice #149469

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 2 commits into
base: main
Choose a base branch
from
Open
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
3 changes: 3 additions & 0 deletions clang/include/clang/Basic/DiagnosticFrontendKinds.td
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down
3 changes: 3 additions & 0 deletions clang/include/clang/Basic/LangOptions.def
Original file line number Diff line number Diff line change
Expand Up @@ -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
17 changes: 17 additions & 0 deletions clang/include/clang/Basic/LangOptions.h
Original file line number Diff line number Diff line change
Expand Up @@ -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,
Expand Down
6 changes: 6 additions & 0 deletions clang/include/clang/Driver/Options.td
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
48 changes: 47 additions & 1 deletion clang/lib/Basic/Targets/OSTargets.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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);
}

Expand Down
1 change: 1 addition & 0 deletions clang/lib/Driver/ToolChains/Clang.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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,
Expand Down
24 changes: 18 additions & 6 deletions clang/lib/Driver/ToolChains/MinGW.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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,
Expand Down
38 changes: 38 additions & 0 deletions clang/lib/Frontend/CompilerInvocation.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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;
}

Expand Down
30 changes: 30 additions & 0 deletions clang/test/Driver/mingw-mcrtdll.c
Original file line number Diff line number Diff line change
@@ -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'
8 changes: 4 additions & 4 deletions clang/test/Driver/mingw-msvcrt.c
Original file line number Diff line number Diff line change
Expand Up @@ -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"
Loading