]> granicus.if.org Git - clang/commitdiff
Driver: Implement majority tool binding logic.
authorDaniel Dunbar <daniel@zuster.org>
Mon, 16 Mar 2009 06:56:51 +0000 (06:56 +0000)
committerDaniel Dunbar <daniel@zuster.org>
Mon, 16 Mar 2009 06:56:51 +0000 (06:56 +0000)
 - Still need code for determining proper output location.

 - Doesn't work yet, of course, as the host isn't providing real
   tool chains.

 - Interface still has a few warts, but has gotten a nice bit of
   polish during the rewrite.

git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@67038 91177308-0d34-0410-b5e6-96231b3b80d8

include/clang/Basic/DiagnosticDriverKinds.def
include/clang/Basic/DiagnosticDriverKinds.td
include/clang/Driver/Driver.h
lib/Driver/Driver.cpp
lib/Driver/InputInfo.h [new file with mode: 0644]
tools/driver/driver.cpp

index d9297678865673df6ed4f64e2be3d10b784774e2..a11435bea062f2497147eb9c9b5f4b7290bad777 100644 (file)
@@ -28,8 +28,12 @@ DIAG(err_drv_no_input_files, ERROR,
      "no input files")
 DIAG(err_drv_use_of_Z_option, ERROR,
      "unsupported use of internal gcc -Z option '%0'")
+DIAG(err_drv_output_argument_with_multiple_files, ERROR,
+     "cannot specify -o when generating multiple output files")
 
 DIAG(warn_drv_input_file_unused, WARNING,
      "%0: '%1' input file unused when '%2' is present")
 DIAG(warn_drv_unused_argument, WARNING,
      "argument unused during compilation: '%0'")
+DIAG(warn_drv_pipe_ignored_with_save_temps, WARNING,
+     "-pipe ignored because -save-temps specified")
index cc7067a4ef328dca6d696da09c145dbc119096c1..df24648dde6bd49c63abb2e96a9269af304d4cd1 100644 (file)
@@ -21,10 +21,14 @@ def err_drv_invalid_output_with_multiple_archs : Error<
 def err_drv_no_input_files : Error<"no input files">;
 def err_drv_use_of_Z_option : Error<
   "unsupported use of internal gcc -Z option '%0'">;
+def err_drv_output_argument_with_multiple_files : Error<
+  "cannot specify -o when generating multiple output files">;
 
 def warn_drv_input_file_unused : Warning<
   "%0: '%1' input file unused when '%2' is present">;
 def warn_drv_unused_argument : Warning<
   "argument unused during compilation: '%0'">;
+def warn_drv_pipe_ignored_with_save_temps : Warning<
+  "-pipe ignored because -save-temps specified">;
 
 }
index 672f173c023f1d51a50fad2af52480a956e06b3a..679259c925e75648711b13b3e94cac48426e9ece 100644 (file)
@@ -27,7 +27,9 @@ namespace driver {
   class ArgList;
   class Compilation;
   class HostInfo;
+  class InputInfo;
   class OptTable;
+  class PipedJob;
   class ToolChain;
 
 /// Driver - Encapsulate logic for constructing compilation processes
@@ -54,6 +56,9 @@ public:
   /// Default host triple.
   std::string DefaultHostTriple;
 
+  /// Default name for linked images (e.g., "a.out").
+  std::string DefaultImageName;
+
   /// Host information for the platform the driver is running as. This
   /// will generally be the actual host platform, but not always.
   HostInfo *Host;
@@ -95,6 +100,7 @@ public:
 public:
   Driver(const char *_Name, const char *_Dir,
          const char *_DefaultHostTriple,
+         const char *_DefaultImageName,
          Diagnostic &_Diags);
   ~Driver();
 
@@ -186,6 +192,17 @@ public:
   Action *ConstructPhaseAction(const ArgList &Args, phases::ID Phase,
                                Action *Input) const;
 
+
+  /// BuildJobsForAction - Construct the jobs to perform for the
+  /// action \arg A.
+  void BuildJobsForAction(Compilation &C,
+                          const Action *A,
+                          const ToolChain *TC,
+                          bool CanAcceptPipe,
+                          bool AtTopLevel,
+                          const char *LinkingOutput,
+                          InputInfo &Result) const;
+
   /// GetHostInfo - Construct a new host info object for the given
   /// host triple.
   static HostInfo *GetHostInfo(const char *HostTriple);
index cba2c9f7c634055915925fd6f495acb44ea3587b..e02c283b7c5f8a5414370d046aa252a4031e90a9 100644 (file)
 #include "clang/Driver/Compilation.h"
 #include "clang/Driver/DriverDiagnostic.h"
 #include "clang/Driver/HostInfo.h"
+#include "clang/Driver/Job.h"
 #include "clang/Driver/Option.h"
 #include "clang/Driver/Options.h"
+#include "clang/Driver/Tool.h"
+#include "clang/Driver/ToolChain.h"
 #include "clang/Driver/Types.h"
 
 #include "llvm/ADT/StringSet.h"
 #include "llvm/Support/raw_ostream.h"
 #include "llvm/System/Path.h"
 
+#include "InputInfo.h"
+
 #include <map>
 
 using namespace clang::driver;
 
 Driver::Driver(const char *_Name, const char *_Dir,
                const char *_DefaultHostTriple,
+               const char *_DefaultImageName,
                Diagnostic &_Diags) 
   : Opts(new OptTable()), Diags(_Diags), 
     Name(_Name), Dir(_Dir), DefaultHostTriple(_DefaultHostTriple),
+    DefaultImageName(_DefaultImageName),
     Host(0),
     CCCIsCXX(false), CCCEcho(false), 
     CCCNoClang(false), CCCNoClangCXX(false), CCCNoClangCPP(false),
@@ -567,8 +574,60 @@ Action *Driver::ConstructPhaseAction(const ArgList &Args, phases::ID Phase,
   return 0;
 }
 
-void Driver::BuildJobs(Compilation &C,
-                       const ActionList &Actions) const {
+void Driver::BuildJobs(Compilation &C, const ActionList &Actions) const {
+  bool SaveTemps = C.getArgs().hasArg(options::OPT_save_temps);
+  bool UsePipes = C.getArgs().hasArg(options::OPT_pipe);
+  
+  // -save-temps inhibits pipes.
+  if (SaveTemps && UsePipes) {
+    Diag(clang::diag::warn_drv_pipe_ignored_with_save_temps);
+    UsePipes = true;
+  }
+
+  Arg *FinalOutput = C.getArgs().getLastArg(options::OPT_o);
+
+  // It is an error to provide a -o option if we are making multiple
+  // output files.
+  if (FinalOutput) {
+    unsigned NumOutputs = 0;
+    for (ActionList::const_iterator it = Actions.begin(), ie = Actions.end(); 
+         it != ie; ++it)
+      if ((*it)->getType() != types::TY_Nothing)
+        ++NumOutputs;
+    
+    if (NumOutputs > 1) {
+      Diag(clang::diag::err_drv_output_argument_with_multiple_files);
+      FinalOutput = 0;
+    }
+  }
+
+  for (ActionList::const_iterator it = Actions.begin(), ie = Actions.end(); 
+       it != ie; ++it) {
+    Action *A = *it;
+
+    // If we are linking an image for multiple archs then the linker
+    // wants -arch_multiple and -final_output <final image
+    // name>. Unfortunately, this doesn't fit in cleanly because we
+    // have to pass this information down.
+    //
+    // FIXME: This is a hack; find a cleaner way to integrate this
+    // into the process.
+    const char *LinkingOutput = 0;
+    if (isa<LinkJobAction>(A)) {
+      if (FinalOutput)
+        LinkingOutput = FinalOutput->getValue(C.getArgs());
+      else
+        LinkingOutput = DefaultImageName.c_str();
+    }
+
+    InputInfo II;
+    BuildJobsForAction(C, 
+                       A, DefaultToolChain, 
+                       /*CanAcceptPipe*/ true,
+                       /*AtTopLevel*/ true,
+                       /*LinkingOutput*/ LinkingOutput,
+                       II);
+  }
 
   // If there were no errors, warn about any unused arguments.
   for (ArgList::const_iterator it = C.getArgs().begin(), ie = C.getArgs().end();
@@ -584,6 +643,91 @@ void Driver::BuildJobs(Compilation &C,
   }
 }
 
+void Driver::BuildJobsForAction(Compilation &C,
+                                const Action *A,
+                                const ToolChain *TC,
+                                bool CanAcceptPipe,
+                                bool AtTopLevel,
+                                const char *LinkingOutput,
+                                InputInfo &Result) const {
+  if (const InputAction *IA = dyn_cast<InputAction>(A)) {
+    const char *Name = IA->getInputArg().getValue(C.getArgs());
+    Result = InputInfo(Name, A->getType(), Name);
+    return;
+  }
+
+  if (const BindArchAction *BAA = dyn_cast<BindArchAction>(A)) {
+    const char *ArchName = BAA->getArchName();
+    BuildJobsForAction(C,
+                       *BAA->begin(), 
+                       Host->getToolChain(C.getArgs(), ArchName),
+                       CanAcceptPipe,
+                       AtTopLevel,
+                       LinkingOutput,
+                       Result);
+    return;
+  }
+
+  const JobAction *JA = cast<JobAction>(A);
+  const Tool &T = TC->SelectTool(C, *JA);
+  
+  // See if we should use an integrated preprocessor. We do so when we
+  // have exactly one input, since this is the only use case we care
+  // about (irrelevant since we don't support combine yet).
+  bool UseIntegratedCPP = false;
+  const ActionList *Inputs = &A->getInputs();
+  if (Inputs->size() == 1 && isa<PreprocessJobAction>(*Inputs->begin())) {
+    if (!C.getArgs().hasArg(options::OPT_no_integrated_cpp) &&
+        !C.getArgs().hasArg(options::OPT_traditional_cpp) &&
+        !C.getArgs().hasArg(options::OPT_save_temps) &&
+        T.hasIntegratedCPP()) {
+      UseIntegratedCPP = true;
+      Inputs = &(*Inputs)[0]->getInputs();
+    }
+  }
+
+  // Only use pipes when there is exactly one input.
+  bool TryToUsePipeInput = Inputs->size() == 1 && T.acceptsPipedInput();
+  llvm::SmallVector<InputInfo, 4> InputInfos;
+  for (ActionList::const_iterator it = Inputs->begin(), ie = Inputs->end();
+       it != ie; ++it) {
+    InputInfo II;
+    BuildJobsForAction(C, *it, TC, TryToUsePipeInput, 
+                       /*AtTopLevel*/false,
+                       LinkingOutput,
+                       II);
+    InputInfos.push_back(II);
+  }
+
+  // Determine if we should output to a pipe.
+  bool OutputToPipe = false;
+  if (CanAcceptPipe && T.canPipeOutput()) {
+    // Some actions default to writing to a pipe if they are the top
+    // level phase and there was no user override.
+    //
+    // FIXME: Is there a better way to handle this?
+    if (AtTopLevel) {
+      if (isa<PreprocessJobAction>(A) && !C.getArgs().hasArg(options::OPT_o))
+        OutputToPipe = true;
+    } else if (C.getArgs().hasArg(options::OPT_pipe))
+      OutputToPipe = true;
+  }
+
+  // Figure out where to put the job (pipes).
+  Job *Dest = &C.getJobs();
+  if (InputInfos[0].isPipe()) {
+    assert(InputInfos.size() == 1 && "Unexpected pipe with multiple inputs.");
+    Dest = &InputInfos[0].getPipe();
+  }
+
+  // Always use the first input as the base input.
+  const char *BaseInput = InputInfos[0].getBaseInput();
+  const char *Output = "foo";
+  // FIXME: Make the job.
+
+  Result = InputInfo(Output, A->getType(), BaseInput);
+}
+
 llvm::sys::Path Driver::GetFilePath(const char *Name,
                                     const ToolChain *TC) const {
   // FIXME: Implement.
diff --git a/lib/Driver/InputInfo.h b/lib/Driver/InputInfo.h
new file mode 100644 (file)
index 0000000..6fedf82
--- /dev/null
@@ -0,0 +1,57 @@
+//===--- InputInfo.h - Input Source & Type Information ----------*- C++ -*-===//
+//
+//                     The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef CLANG_LIB_DRIVER_INPUTINFO_H_
+#define CLANG_LIB_DRIVER_INPUTINFO_H_
+
+#include <cassert>
+
+namespace clang {
+namespace driver {
+  class PipedJob;
+
+/// InputInfo - Wrapper for information about an input source.
+class InputInfo {
+  union {
+    const char *Filename;
+    PipedJob *Pipe;
+  } Data;
+  bool IsPipe;
+  types::ID Type;
+  const char *BaseInput;
+
+public:
+  InputInfo() {}
+  InputInfo(const char *Filename, types::ID _Type, const char *_BaseInput)
+    : IsPipe(false), Type(_Type), BaseInput(_BaseInput) {
+    Data.Filename = Filename;
+  }
+  InputInfo(PipedJob *Pipe, types::ID _Type, const char *_BaseInput)
+    : IsPipe(true), Type(_Type), BaseInput(_BaseInput) {
+    Data.Pipe = Pipe;
+  }
+
+  bool isPipe() const { return IsPipe; }
+  types::ID getType() const { return Type; }
+  const char *getBaseInput() const { return BaseInput; }
+
+  const char *getInputFilename() const {
+    assert(!isPipe() && "Invalid accessor.");
+    return Data.Filename;
+  }
+  PipedJob &getPipe() const {
+    assert(isPipe() && "Invalid accessor.");
+    return *Data.Pipe;
+  }
+};
+
+} // end namespace driver
+} // end namespace clang
+
+#endif
index fd0cc9cbb8a5907bedfc91d1eddc6e4662e4077e..308ec01133e531695d1cb44ca10f6260cbd70648 100644 (file)
@@ -45,6 +45,7 @@ int main(int argc, const char **argv) {
   llvm::OwningPtr<Driver> TheDriver(new Driver(Path.getBasename().c_str(),
                                                Path.getDirname().c_str(),
                                                LLVM_HOSTTRIPLE,
+                                               "a.out",
                                                Diags));
                                                
   llvm::OwningPtr<Compilation> C(TheDriver->BuildCompilation(argc, argv));