diff options
author | Daniel Dunbar <daniel@zuster.org> | 2009-03-16 06:56:51 +0000 |
---|---|---|
committer | Daniel Dunbar <daniel@zuster.org> | 2009-03-16 06:56:51 +0000 |
commit | f353c8cc2ee1cc16ff194b399a8d951f707fb129 (patch) | |
tree | 942b053e916f0d9308ba25c356fc2ced09ebe462 | |
parent | 586dc233bb88f2920c9f3638f69cef0ccd55dced (diff) |
Driver: Implement majority tool binding logic.
- 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
-rw-r--r-- | include/clang/Basic/DiagnosticDriverKinds.def | 4 | ||||
-rw-r--r-- | include/clang/Basic/DiagnosticDriverKinds.td | 4 | ||||
-rw-r--r-- | include/clang/Driver/Driver.h | 17 | ||||
-rw-r--r-- | lib/Driver/Driver.cpp | 148 | ||||
-rw-r--r-- | lib/Driver/InputInfo.h | 57 | ||||
-rw-r--r-- | tools/driver/driver.cpp | 1 |
6 files changed, 229 insertions, 2 deletions
diff --git a/include/clang/Basic/DiagnosticDriverKinds.def b/include/clang/Basic/DiagnosticDriverKinds.def index d929767886..a11435bea0 100644 --- a/include/clang/Basic/DiagnosticDriverKinds.def +++ b/include/clang/Basic/DiagnosticDriverKinds.def @@ -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") diff --git a/include/clang/Basic/DiagnosticDriverKinds.td b/include/clang/Basic/DiagnosticDriverKinds.td index cc7067a4ef..df24648dde 100644 --- a/include/clang/Basic/DiagnosticDriverKinds.td +++ b/include/clang/Basic/DiagnosticDriverKinds.td @@ -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">; } diff --git a/include/clang/Driver/Driver.h b/include/clang/Driver/Driver.h index 672f173c02..679259c925 100644 --- a/include/clang/Driver/Driver.h +++ b/include/clang/Driver/Driver.h @@ -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); diff --git a/lib/Driver/Driver.cpp b/lib/Driver/Driver.cpp index cba2c9f7c6..e02c283b7c 100644 --- a/lib/Driver/Driver.cpp +++ b/lib/Driver/Driver.cpp @@ -15,23 +15,30 @@ #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 index 0000000000..6fedf82a99 --- /dev/null +++ b/lib/Driver/InputInfo.h @@ -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 diff --git a/tools/driver/driver.cpp b/tools/driver/driver.cpp index fd0cc9cbb8..308ec01133 100644 --- a/tools/driver/driver.cpp +++ b/tools/driver/driver.cpp @@ -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)); |