diff --git a/clang/include/clang/Driver/Options.td b/clang/include/clang/Driver/Options.td --- a/clang/include/clang/Driver/Options.td +++ b/clang/include/clang/Driver/Options.td @@ -2211,6 +2211,14 @@ HelpText<"Dot-separated value representing the Microsoft compiler " "version number to report in _MSC_VER (0 = don't define it " "(default))">; +def fms_runtime_lib_EQ : Joined<["-"], "fms-runtime-lib=">, Group, + Flags<[NoXarchOption, CoreOption]>, Values<"static,static_dbg,dll,dll_dbg">, + HelpText<"Select Windows run-time library">, + DocBrief<[{ +Specify Visual Studio C runtime library. "static" and "static_dbg" correspond +to the cl flags /MT and /MTd which use the multithread, static version. "dll" +and "dll_dbg" correspond to the cl flags /MD and /MDd which use the multithread, +dll version.}]>; defm delayed_template_parsing : BoolFOption<"delayed-template-parsing", LangOpts<"DelayedTemplateParsing">, DefaultFalse, PosFlag, diff --git a/clang/lib/Driver/ToolChains/Clang.cpp b/clang/lib/Driver/ToolChains/Clang.cpp --- a/clang/lib/Driver/ToolChains/Clang.cpp +++ b/clang/lib/Driver/ToolChains/Clang.cpp @@ -4436,6 +4436,82 @@ RenderDebugInfoCompressionArgs(Args, CmdArgs, D, TC); } +static void ProcessVSRuntimeLibrary(const ArgList &Args, + ArgStringList &CmdArgs, + bool IsClangCL) { + unsigned RTOptionID = 0; // MT=0, MTd=1, MD=2, MDd=3 + bool HasLDdFlag = IsClangCL && Args.hasArg(options::OPT__SLASH_LDd); + + if (Args.hasArg(options::OPT__SLASH_LDd)) + // The /LDd option implies /MTd. The dependent lib part can be overridden, + // but defining _DEBUG is sticky. + RTOptionID = 1; // options::OPT__SLASH_MTd; + + if (IsClangCL) { + if (Arg *A = Args.getLastArg(options::OPT__SLASH_M_Group)) { + switch (A->getOption().getID()) { + case options::OPT__SLASH_MT: RTOptionID = 0; break; + case options::OPT__SLASH_MTd: RTOptionID = 1; break; + case options::OPT__SLASH_MD: RTOptionID = 2; break; + case options::OPT__SLASH_MDd: RTOptionID = 3; break; + default: llvm_unreachable("Unexpected option ID."); + } + } + } else { + if (Arg *A = Args.getLastArg(options::OPT_fms_runtime_lib_EQ)) { + StringRef Val = A->getValue(); + if (Val == "static") RTOptionID = 0; + else if (Val == "static_dbg") RTOptionID = 1; + else if (Val == "dll") RTOptionID = 2; + else if (Val == "dll_dbg") RTOptionID = 3; + else llvm_unreachable("Unexpected option ID."); + } + } + + StringRef FlagForCRT; + switch (RTOptionID) { + case 2: // MD + if (HasLDdFlag) + CmdArgs.push_back("-D_DEBUG"); + CmdArgs.push_back("-D_MT"); + CmdArgs.push_back("-D_DLL"); + FlagForCRT = "--dependent-lib=msvcrt"; + break; + case 3: // MDd + CmdArgs.push_back("-D_DEBUG"); + CmdArgs.push_back("-D_MT"); + CmdArgs.push_back("-D_DLL"); + FlagForCRT = "--dependent-lib=msvcrtd"; + break; + case 0: // MT + if (HasLDdFlag) + CmdArgs.push_back("-D_DEBUG"); + CmdArgs.push_back("-D_MT"); + CmdArgs.push_back("-flto-visibility-public-std"); + FlagForCRT = "--dependent-lib=libcmt"; + break; + case 1: // MTd + CmdArgs.push_back("-D_DEBUG"); + CmdArgs.push_back("-D_MT"); + CmdArgs.push_back("-flto-visibility-public-std"); + FlagForCRT = "--dependent-lib=libcmtd"; + break; + default: + llvm_unreachable("Unexpected option ID."); + } + + if (IsClangCL && Args.hasArg(options::OPT__SLASH_Zl)) { + CmdArgs.push_back("-D_VC_NODEFAULTLIB"); + } else { + CmdArgs.push_back(FlagForCRT.data()); + + // This provides POSIX compatibility (maps 'open' to '_open'), which most + // users want. The /Za flag to cl.exe turns this off, but it's not + // implemented in clang. + CmdArgs.push_back("--dependent-lib=oldnames"); + } +} + void Clang::ConstructJob(Compilation &C, const JobAction &JA, const InputInfo &Output, const InputInfoList &Inputs, const ArgList &Args, const char *LinkingOutput) const { @@ -6484,6 +6560,9 @@ if (IsMSVCCompat) CmdArgs.push_back("-fms-compatibility"); + if (Triple.isOSWindows() && !D.IsCLMode()) + ProcessVSRuntimeLibrary(Args, CmdArgs, /*IsClangCL*/false); + // Handle -fgcc-version, if present. VersionTuple GNUCVer; if (Arg *A = Args.getLastArg(options::OPT_fgnuc_version_EQ)) { @@ -7534,59 +7613,9 @@ ArgStringList &CmdArgs, codegenoptions::DebugInfoKind *DebugInfoKind, bool *EmitCodeView) const { - unsigned RTOptionID = options::OPT__SLASH_MT; bool isNVPTX = getToolChain().getTriple().isNVPTX(); - if (Args.hasArg(options::OPT__SLASH_LDd)) - // The /LDd option implies /MTd. The dependent lib part can be overridden, - // but defining _DEBUG is sticky. - RTOptionID = options::OPT__SLASH_MTd; - - if (Arg *A = Args.getLastArg(options::OPT__SLASH_M_Group)) - RTOptionID = A->getOption().getID(); - - StringRef FlagForCRT; - switch (RTOptionID) { - case options::OPT__SLASH_MD: - if (Args.hasArg(options::OPT__SLASH_LDd)) - CmdArgs.push_back("-D_DEBUG"); - CmdArgs.push_back("-D_MT"); - CmdArgs.push_back("-D_DLL"); - FlagForCRT = "--dependent-lib=msvcrt"; - break; - case options::OPT__SLASH_MDd: - CmdArgs.push_back("-D_DEBUG"); - CmdArgs.push_back("-D_MT"); - CmdArgs.push_back("-D_DLL"); - FlagForCRT = "--dependent-lib=msvcrtd"; - break; - case options::OPT__SLASH_MT: - if (Args.hasArg(options::OPT__SLASH_LDd)) - CmdArgs.push_back("-D_DEBUG"); - CmdArgs.push_back("-D_MT"); - CmdArgs.push_back("-flto-visibility-public-std"); - FlagForCRT = "--dependent-lib=libcmt"; - break; - case options::OPT__SLASH_MTd: - CmdArgs.push_back("-D_DEBUG"); - CmdArgs.push_back("-D_MT"); - CmdArgs.push_back("-flto-visibility-public-std"); - FlagForCRT = "--dependent-lib=libcmtd"; - break; - default: - llvm_unreachable("Unexpected option ID."); - } - - if (Args.hasArg(options::OPT__SLASH_Zl)) { - CmdArgs.push_back("-D_VC_NODEFAULTLIB"); - } else { - CmdArgs.push_back(FlagForCRT.data()); - - // This provides POSIX compatibility (maps 'open' to '_open'), which most - // users want. The /Za flag to cl.exe turns this off, but it's not - // implemented in clang. - CmdArgs.push_back("--dependent-lib=oldnames"); - } + ProcessVSRuntimeLibrary(Args, CmdArgs, /*IsClangCL*/true); if (Arg *ShowIncludes = Args.getLastArg(options::OPT__SLASH_showIncludes, diff --git a/clang/test/Driver/cl-runtime-flags.c b/clang/test/Driver/cl-runtime-flags.c --- a/clang/test/Driver/cl-runtime-flags.c +++ b/clang/test/Driver/cl-runtime-flags.c @@ -10,6 +10,8 @@ // RUN: %clang_cl -### -- %s 2>&1 | FileCheck -check-prefix=CHECK-MT %s // RUN: %clang_cl -### /MT -- %s 2>&1 | FileCheck -check-prefix=CHECK-MT %s +// RUN: %clang -### --target=x86_64-windows-msvc -fms-runtime-lib=static -- %s \ +// RUN: 2>&1 | FileCheck -check-prefix=CHECK-MT %s // CHECK-MT-NOT: "-D_DEBUG" // CHECK-MT: "-D_MT" // CHECK-MT-NOT: "-D_DLL" @@ -19,6 +21,8 @@ // RUN: %clang_cl -### /MTd -- %s 2>&1 | FileCheck -check-prefix=CHECK-MTd %s // RUN: %clang_cl -### /LD /MTd -- %s 2>&1 | FileCheck -check-prefix=CHECK-MTd %s +// RUN: %clang -### --target=x86_64-windows-msvc -fms-runtime-lib=static_dbg \ +// RUN: -- %s 2>&1 | FileCheck -check-prefix=CHECK-MTd %s // CHECK-MTd: "-D_DEBUG" // CHECK-MTd: "-D_MT" // CHECK-MTd-NOT: "-D_DLL" @@ -27,6 +31,8 @@ // CHECK-MTd: "--dependent-lib=oldnames" // RUN: %clang_cl -### /MD -- %s 2>&1 | FileCheck -check-prefix=CHECK-MD %s +// RUN: %clang -### --target=x86_64-windows-msvc -fms-runtime-lib=dll -- %s \ +// RUN: 2>&1 | FileCheck -check-prefix=CHECK-MD %s // CHECK-MD-NOT: "-D_DEBUG" // CHECK-MD: "-D_MT" // CHECK-MD: "-D_DLL" @@ -34,6 +40,8 @@ // CHECK-MD: "--dependent-lib=oldnames" // RUN: %clang_cl -### /MDd -- %s 2>&1 | FileCheck -check-prefix=CHECK-MDd %s +// RUN: %clang -### --target=x86_64-windows-msvc -fms-runtime-lib=dll_dbg -- \ +// RUN: %s 2>&1 | FileCheck -check-prefix=CHECK-MDd %s // CHECK-MDd: "-D_DEBUG" // CHECK-MDd: "-D_MT" // CHECK-MDd: "-D_DLL"