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