clang-cl: implement /fallback mode
When this flag is enabled, clang-cl falls back to cl.exe if it
cannot compile the code itself for some reason.
The idea is to use this to help build projects that almost compile
with clang-cl, except for some files that can then be built with
the fallback mechanism.
Differential Revision: http://llvm-reviews.chandlerc.com/D1711
git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@191034 91177308-0d34-0410-b5e6-96231b3b80d8
diff --git a/lib/Driver/Tools.cpp b/lib/Driver/Tools.cpp
index da27a94..a9d3acc 100644
--- a/lib/Driver/Tools.cpp
+++ b/lib/Driver/Tools.cpp
@@ -3565,7 +3565,15 @@
}
// Finally add the compile command to the compilation.
- C.addCommand(new Command(JA, *this, Exec, CmdArgs));
+ if (Args.hasArg(options::OPT__SLASH_fallback)) {
+ tools::visualstudio::Compile CL(getToolChain());
+ Command *CLCommand = CL.GetCommand(C, JA, Output, Inputs, Args,
+ LinkingOutput);
+ C.addCommand(new FallbackCommand(JA, *this, Exec, CmdArgs, CLCommand));
+ } else {
+ C.addCommand(new Command(JA, *this, Exec, CmdArgs));
+ }
+
// Handle the debug info splitting at object creation time if we're
// creating an object.
@@ -6638,3 +6646,70 @@
Args.MakeArgString(getToolChain().GetProgramPath("link.exe"));
C.addCommand(new Command(JA, *this, Exec, CmdArgs));
}
+
+void visualstudio::Compile::ConstructJob(Compilation &C, const JobAction &JA,
+ const InputInfo &Output,
+ const InputInfoList &Inputs,
+ const ArgList &Args,
+ const char *LinkingOutput) const {
+ C.addCommand(GetCommand(C, JA, Output, Inputs, Args, LinkingOutput));
+}
+
+Command *visualstudio::Compile::GetCommand(Compilation &C, const JobAction &JA,
+ const InputInfo &Output,
+ const InputInfoList &Inputs,
+ const ArgList &Args,
+ const char *LinkingOutput) const {
+ ArgStringList CmdArgs;
+ CmdArgs.push_back("/c"); // Compile only.
+ CmdArgs.push_back("/W0"); // No warnings.
+
+ // The goal is to be able to invoke this tool correctly based on
+ // any flag accepted by clang-cl.
+
+ // These are spelled the same way in clang and cl.exe,.
+ Args.AddAllArgs(CmdArgs, options::OPT_D, options::OPT_U);
+ Args.AddAllArgs(CmdArgs, options::OPT_I);
+ Args.AddLastArg(CmdArgs, options::OPT_O, options::OPT_O0);
+
+ // Flags for which clang-cl have an alias.
+ // FIXME: How can we ensure this stays in sync with relevant clang-cl options?
+
+ if (Arg *A = Args.getLastArg(options::OPT_frtti, options::OPT_fno_rtti))
+ CmdArgs.push_back(A->getOption().getID() == options::OPT_frtti ? "/GR"
+ : "/GR-");
+ if (Args.hasArg(options::OPT_fsyntax_only))
+ CmdArgs.push_back("/Zs");
+
+ // Flags that can simply be passed through.
+ Args.AddAllArgs(CmdArgs, options::OPT__SLASH_LD);
+ Args.AddAllArgs(CmdArgs, options::OPT__SLASH_LDd);
+
+ // The order of these flags is relevant, so pick the last one.
+ if (Arg *A = Args.getLastArg(options::OPT__SLASH_MD, options::OPT__SLASH_MDd,
+ options::OPT__SLASH_MT, options::OPT__SLASH_MTd))
+ A->render(Args, CmdArgs);
+
+
+ // Input filename.
+ assert(Inputs.size() == 1);
+ const InputInfo &II = Inputs[0];
+ assert(II.getType() == types::TY_C || II.getType() == types::TY_CXX);
+ CmdArgs.push_back(II.getType() == types::TY_C ? "/Tc" : "/Tp");
+ if (II.isFilename())
+ CmdArgs.push_back(II.getFilename());
+ else
+ II.getInputArg().renderAsInput(Args, CmdArgs);
+
+ // Output filename.
+ assert(Output.getType() == types::TY_Object);
+ const char *Fo = Args.MakeArgString(std::string("/Fo") +
+ Output.getFilename());
+ CmdArgs.push_back(Fo);
+
+ // FIXME: If we've put clang-cl as cl.exe on the path, we have a problem.
+ const char *Exec =
+ Args.MakeArgString(getToolChain().GetProgramPath("cl.exe"));
+
+ return new Command(JA, *this, Exec, CmdArgs);
+}