r191034 - clang-cl: implement /fallback mode

Hans Wennborg hans at hanshq.net
Thu Sep 19 13:32:17 PDT 2013


Author: hans
Date: Thu Sep 19 15:32:16 2013
New Revision: 191034

URL: http://llvm.org/viewvc/llvm-project?rev=191034&view=rev
Log:
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

Added:
    cfe/trunk/test/Driver/cl-fallback.c
Modified:
    cfe/trunk/include/clang/Driver/CLCompatOptions.td
    cfe/trunk/include/clang/Driver/Job.h
    cfe/trunk/include/clang/Driver/Tool.h
    cfe/trunk/lib/Driver/Job.cpp
    cfe/trunk/lib/Driver/Tools.cpp
    cfe/trunk/lib/Driver/Tools.h

Modified: cfe/trunk/include/clang/Driver/CLCompatOptions.td
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Driver/CLCompatOptions.td?rev=191034&r1=191033&r2=191034&view=diff
==============================================================================
--- cfe/trunk/include/clang/Driver/CLCompatOptions.td (original)
+++ cfe/trunk/include/clang/Driver/CLCompatOptions.td Thu Sep 19 15:32:16 2013
@@ -110,6 +110,8 @@ def _SLASH_Zs : CLFlag<"Zs">, HelpText<"
 
 def _SLASH_M_Group : OptionGroup<"</M group>">, Group<cl_compile_Group>;
 
+def _SLASH_fallback : CLCompileFlag<"fallback">,
+  HelpText<"Fall back to cl.exe if clang-cl fails to compile">;
 def _SLASH_Fe : CLJoined<"Fe">,
   HelpText<"Set output executable file or directory (ends in / or \\)">,
   MetaVarName<"<file or directory>">;

Modified: cfe/trunk/include/clang/Driver/Job.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Driver/Job.h?rev=191034&r1=191033&r2=191034&view=diff
==============================================================================
--- cfe/trunk/include/clang/Driver/Job.h (original)
+++ cfe/trunk/include/clang/Driver/Job.h Thu Sep 19 15:32:16 2013
@@ -11,6 +11,7 @@
 #define CLANG_DRIVER_JOB_H_
 
 #include "clang/Basic/LLVM.h"
+#include "llvm/ADT/OwningPtr.h"
 #include "llvm/ADT/SmallVector.h"
 #include "llvm/Option/Option.h"
 
@@ -31,6 +32,7 @@ class Job {
 public:
   enum JobClass {
     CommandClass,
+    FallbackCommandClass,
     JobListClass
   };
 
@@ -54,8 +56,8 @@ public:
                      bool Quote, bool CrashReport = false) const = 0;
 };
 
-  /// Command - An executable path/name and argument vector to
-  /// execute.
+/// Command - An executable path/name and argument vector to
+/// execute.
 class Command : public Job {
   /// Source - The action which caused the creation of this job.
   const Action &Source;
@@ -77,8 +79,8 @@ public:
   virtual void Print(llvm::raw_ostream &OS, const char *Terminator,
                      bool Quote, bool CrashReport = false) const;
 
-  int Execute(const StringRef **Redirects, std::string *ErrMsg,
-              bool *ExecutionFailed) const;
+  virtual int Execute(const StringRef **Redirects, std::string *ErrMsg,
+                      bool *ExecutionFailed) const;
 
   /// getSource - Return the Action which caused the creation of this job.
   const Action &getSource() const { return Source; }
@@ -89,11 +91,34 @@ public:
   const llvm::opt::ArgStringList &getArguments() const { return Arguments; }
 
   static bool classof(const Job *J) {
-    return J->getKind() == CommandClass;
+    return J->getKind() == CommandClass ||
+           J->getKind() == FallbackCommandClass;
   }
 };
 
-  /// JobList - A sequence of jobs to perform.
+/// Like Command, but with a fallback which is executed in case
+/// the primary command crashes.
+class FallbackCommand : public Command {
+public:
+  FallbackCommand(const Action &Source_, const Tool &Creator_,
+                  const char *Executable_, const ArgStringList &Arguments_,
+                  Command *Fallback_);
+
+  virtual void Print(llvm::raw_ostream &OS, const char *Terminator,
+                     bool Quote, bool CrashReport = false) const;
+
+  virtual int Execute(const StringRef **Redirects, std::string *ErrMsg,
+                      bool *ExecutionFailed) const;
+
+  static bool classof(const Job *J) {
+    return J->getKind() == FallbackCommandClass;
+  }
+
+private:
+  OwningPtr<Command> Fallback;
+};
+
+/// JobList - A sequence of jobs to perform.
 class JobList : public Job {
 public:
   typedef SmallVector<Job*, 4> list_type;

Modified: cfe/trunk/include/clang/Driver/Tool.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Driver/Tool.h?rev=191034&r1=191033&r2=191034&view=diff
==============================================================================
--- cfe/trunk/include/clang/Driver/Tool.h (original)
+++ cfe/trunk/include/clang/Driver/Tool.h Thu Sep 19 15:32:16 2013
@@ -63,7 +63,8 @@ public:
   virtual bool hasGoodDiagnostics() const { return false; }
 
   /// ConstructJob - Construct jobs to perform the action \p JA,
-  /// writing to \p Output and with \p Inputs.
+  /// writing to \p Output and with \p Inputs, and add the jobs to
+  /// \p C.
   ///
   /// \param TCArgs - The argument list for this toolchain, with any
   /// tool chain specific translations applied.

Modified: cfe/trunk/lib/Driver/Job.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Driver/Job.cpp?rev=191034&r1=191033&r2=191034&view=diff
==============================================================================
--- cfe/trunk/lib/Driver/Job.cpp (original)
+++ cfe/trunk/lib/Driver/Job.cpp Thu Sep 19 15:32:16 2013
@@ -126,6 +126,43 @@ int Command::Execute(const StringRef **R
                                    /*memoryLimit*/ 0, ErrMsg, ExecutionFailed);
 }
 
+FallbackCommand::FallbackCommand(const Action &Source_, const Tool &Creator_,
+                                 const char *Executable_,
+                                 const ArgStringList &Arguments_,
+                                 Command *Fallback_)
+    : Command(Source_, Creator_, Executable_, Arguments_), Fallback(Fallback_) {
+}
+
+void FallbackCommand::Print(raw_ostream &OS, const char *Terminator,
+                            bool Quote, bool CrashReport) const {
+  Command::Print(OS, "", Quote, CrashReport);
+  OS << " ||";
+  Fallback->Print(OS, Terminator, Quote, CrashReport);
+}
+
+static bool ShouldFallback(int ExitCode) {
+  // FIXME: We really just want to fall back for internal errors, such
+  // as when some symbol cannot be mangled, when we should be able to
+  // parse something but can't, etc.
+  return ExitCode != 0;
+}
+
+int FallbackCommand::Execute(const StringRef **Redirects, std::string *ErrMsg,
+                             bool *ExecutionFailed) const {
+  int PrimaryStatus = Command::Execute(Redirects, ErrMsg, ExecutionFailed);
+  if (!ShouldFallback(PrimaryStatus))
+    return PrimaryStatus;
+
+  // Clear ExecutionFailed and ErrMsg before falling back.
+  if (ErrMsg)
+    ErrMsg->clear();
+  if (ExecutionFailed)
+    *ExecutionFailed = false;
+
+  int SecondaryStatus = Fallback->Execute(Redirects, ErrMsg, ExecutionFailed);
+  return SecondaryStatus;
+}
+
 JobList::JobList() : Job(JobListClass) {}
 
 JobList::~JobList() {

Modified: cfe/trunk/lib/Driver/Tools.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Driver/Tools.cpp?rev=191034&r1=191033&r2=191034&view=diff
==============================================================================
--- cfe/trunk/lib/Driver/Tools.cpp (original)
+++ cfe/trunk/lib/Driver/Tools.cpp Thu Sep 19 15:32:16 2013
@@ -3565,7 +3565,15 @@ void Clang::ConstructJob(Compilation &C,
   }
 
   // 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 @@ void visualstudio::Link::ConstructJob(Co
     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);
+}

Modified: cfe/trunk/lib/Driver/Tools.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Driver/Tools.h?rev=191034&r1=191033&r2=191034&view=diff
==============================================================================
--- cfe/trunk/lib/Driver/Tools.h (original)
+++ cfe/trunk/lib/Driver/Tools.h Thu Sep 19 15:32:16 2013
@@ -21,6 +21,7 @@ namespace clang {
   class ObjCRuntime;
 
 namespace driver {
+  class Command;
   class Driver;
 
 namespace toolchains {
@@ -590,7 +591,7 @@ namespace dragonfly {
 
   /// Visual studio tools.
 namespace visualstudio {
-  class LLVM_LIBRARY_VISIBILITY Link : public Tool  {
+  class LLVM_LIBRARY_VISIBILITY Link : public Tool {
   public:
     Link(const ToolChain &TC) : Tool("visualstudio::Link", "linker", TC) {}
 
@@ -603,6 +604,27 @@ namespace visualstudio {
                               const llvm::opt::ArgList &TCArgs,
                               const char *LinkingOutput) const;
   };
+
+  class LLVM_LIBRARY_VISIBILITY Compile : public Tool {
+  public:
+    Compile(const ToolChain &TC) : Tool("visualstudio::Compile", "compiler", TC) {}
+
+    virtual bool hasIntegratedAssembler() const { return true; }
+    virtual bool hasIntegratedCPP() const { return true; }
+    virtual bool isLinkJob() const { return false; }
+
+    virtual void ConstructJob(Compilation &C, const JobAction &JA,
+                              const InputInfo &Output,
+                              const InputInfoList &Inputs,
+                              const llvm::opt::ArgList &TCArgs,
+                              const char *LinkingOutput) const;
+
+    Command *GetCommand(Compilation &C, const JobAction &JA,
+                        const InputInfo &Output,
+                        const InputInfoList &Inputs,
+                        const llvm::opt::ArgList &TCArgs,
+                        const char *LinkingOutput) const;
+  };
 } // end namespace visualstudio
 
 } // end namespace toolchains

Added: cfe/trunk/test/Driver/cl-fallback.c
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/Driver/cl-fallback.c?rev=191034&view=auto
==============================================================================
--- cfe/trunk/test/Driver/cl-fallback.c (added)
+++ cfe/trunk/test/Driver/cl-fallback.c Thu Sep 19 15:32:16 2013
@@ -0,0 +1,22 @@
+// Don't attempt slash switches on msys bash.
+// REQUIRES: shell-preserves-root
+
+// Note: %s must be preceded by --, otherwise it may be interpreted as a
+// command-line option, e.g. on Mac where %s is commonly under /Users.
+
+// RUN: %clang_cl /fallback /Dfoo=bar /Ubaz /Ifoo /O0 /Ox /GR /GR- /LD /LDd \
+// RUN:     /MD /MDd /MTd /MT -### -- %s 2>&1 | FileCheck %s
+// CHECK: ||
+// CHECK: cl.exe
+// CHECK: "/c"
+// CHECK: "/W0"
+// CHECK: "-D" "foo=bar"
+// CHECK: "-U" "baz"
+// CHECK: "-I" "foo"
+// CHECK: "-O3"
+// CHECK: "/GR-"
+// CHECK: "/LD"
+// CHECK: "/LDd"
+// CHECK: "/MT"
+// CHECK: "/Tc" "{{.*cl-fallback.c}}"
+// CHECK: "/Fo{{.*cl-fallback.*.obj}}"





More information about the cfe-commits mailing list