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 @@ -4437,6 +4437,71 @@ RenderDebugInfoCompressionArgs(Args, CmdArgs, D, TC); } +static void ProcessVSRuntimeLibrary(const ArgList &Args, + ArgStringList &CmdArgs) { + unsigned RTOptionID = options::OPT__SLASH_MT; + + 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(); + + if (Arg *A = Args.getLastArg(options::OPT_fms_runtime_lib_EQ)) { + RTOptionID = llvm::StringSwitch(A->getValue()) + .Case("static", options::OPT__SLASH_MT) + .Case("static_dbg", options::OPT__SLASH_MTd) + .Case("dll", options::OPT__SLASH_MD) + .Case("dll_dbg", options::OPT__SLASH_MDd) + .Default(options::OPT__SLASH_MT); + } + + 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"); + } +} + void Clang::ConstructJob(Compilation &C, const JobAction &JA, const InputInfo &Output, const InputInfoList &Inputs, const ArgList &Args, const char *LinkingOutput) const { @@ -6478,6 +6543,9 @@ if (IsMSVCCompat) CmdArgs.push_back("-fms-compatibility"); + if (Triple.isWindowsMSVCEnvironment() && !D.IsCLMode()) + ProcessVSRuntimeLibrary(Args, CmdArgs); + // Handle -fgcc-version, if present. VersionTuple GNUCVer; if (Arg *A = Args.getLastArg(options::OPT_fgnuc_version_EQ)) { @@ -7528,59 +7596,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); 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"