diff --git a/clang/include/clang/Driver/Action.h b/clang/include/clang/Driver/Action.h new file mode 100644 index 000000000000..12ded40de9b6 --- /dev/null +++ b/clang/include/clang/Driver/Action.h @@ -0,0 +1,28 @@ +//===--- Action.h - Abstract compilation steps ------------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#ifndef CLANG_DRIVER_ACTION_H_ +#define CLANG_DRIVER_ACTION_H_ + +namespace clang { +namespace driver { + +/// Action - Represent an abstract compilation step to perform. +/// +/// An action represents an edge in the compilation graph; typically +/// it is a job to transform an input using some tool. +class Action { +public: + +}; + +} // end namespace driver +} // end namespace clang + +#endif diff --git a/clang/include/clang/Driver/Driver.h b/clang/include/clang/Driver/Driver.h index 38451c66b15c..12b2264c3dab 100644 --- a/clang/include/clang/Driver/Driver.h +++ b/clang/include/clang/Driver/Driver.h @@ -14,8 +14,14 @@ #include #include +namespace llvm { + template class SmallVector; + class raw_ostream; +} + namespace clang { namespace driver { + class Action; class ArgList; class Compilation; class HostInfo; @@ -80,19 +86,39 @@ public: const char *_DefaultHostTriple); ~Driver(); - const OptTable &getOpts() const { return *Opts; } /// BuildCompilation - Construct a compilation object for a command /// line argument vector. Compilation *BuildCompilation(int argc, const char **argv); - /// PrintOptions - Print the given list of arguments. - void PrintOptions(const ArgList *Args); + /// PrintOptions - Print the list of arguments. + void PrintOptions(const ArgList &Args); + + /// PrintActions - Print the list of actions. + void PrintActions(const llvm::SmallVector &Actions); /// GetHostInfo - Construct a new host info object for the given /// host triple. static HostInfo *GetHostInfo(const char *HostTriple); + + /// BuildUniversalActions - Construct the list of actions to perform + /// for the given arguments, which may require a universal build. + /// + /// \param Args - The input arguments. + /// \param Actions - The list to store the resulting actions onto. + void BuildUniversalActions(const ArgList &Args, + llvm::SmallVector &Actions); + + /// BuildActions - Construct the list of actions to perform for the + /// given arguments, which are only done for a single architecture. + /// + /// \param Args - The input arguments. + /// \param Actions - The list to store the resulting actions onto. + void BuildActions(const ArgList &Args, + llvm::SmallVector &Actions); + + llvm::raw_ostream &Diag(const char *Message) const; }; } // end namespace driver diff --git a/clang/lib/Driver/Driver.cpp b/clang/lib/Driver/Driver.cpp index 4b29ae394cf8..d9ed37b7de48 100644 --- a/clang/lib/Driver/Driver.cpp +++ b/clang/lib/Driver/Driver.cpp @@ -9,14 +9,17 @@ #include "clang/Driver/Driver.h" +#include "clang/Driver/Action.h" #include "clang/Driver/Arg.h" #include "clang/Driver/ArgList.h" #include "clang/Driver/Compilation.h" #include "clang/Driver/HostInfo.h" #include "clang/Driver/Option.h" #include "clang/Driver/Options.h" +#include "clang/Driver/Types.h" #include "llvm/Support/raw_ostream.h" +#include "llvm/System/Path.h" using namespace clang::driver; Driver::Driver(const char *_Name, const char *_Dir, @@ -41,8 +44,14 @@ ArgList *Driver::ParseArgStrings(const char **ArgBegin, const char **ArgEnd) { while (Index < End) { unsigned Prev = Index; Arg *A = getOpts().ParseOneArg(*Args, Index, End); - if (A) + if (A) { + if (A->getOption().isUnsupported()) { + Diag("unsupported option: ") << A->getOption().getName() << "\n"; + continue; + } + Args->append(A); + } assert(Index > Prev && "Parser failed to consume argument."); } @@ -53,7 +62,7 @@ ArgList *Driver::ParseArgStrings(const char **ArgBegin, const char **ArgEnd) { Compilation *Driver::BuildCompilation(int argc, const char **argv) { // FIXME: This stuff needs to go into the Compilation, not the // driver. - bool CCCPrintOptions = false, CCCPrintPhases = false; + bool CCCPrintOptions = false, CCCPrintActions = false; const char **Start = argv + 1, **End = argv + argc; const char *HostTriple = DefaultHostTriple.c_str(); @@ -70,7 +79,7 @@ Compilation *Driver::BuildCompilation(int argc, const char **argv) { if (!strcmp(Opt, "print-options")) { CCCPrintOptions = true; } else if (!strcmp(Opt, "print-phases")) { - CCCPrintPhases = true; + CCCPrintActions = true; } else if (!strcmp(Opt, "cxx")) { CCCIsCXX = true; } else if (!strcmp(Opt, "echo")) { @@ -115,18 +124,32 @@ Compilation *Driver::BuildCompilation(int argc, const char **argv) { // FIXME: This behavior shouldn't be here. if (CCCPrintOptions) { - PrintOptions(Args); + PrintOptions(*Args); exit(0); } - + + // Construct the list of abstract actions to perform for this + // compilation. + llvm::SmallVector Actions; + if (Host->useDriverDriver()) + BuildUniversalActions(*Args, Actions); + else + BuildActions(*Args, Actions); + + // FIXME: This behavior shouldn't be here. + if (CCCPrintActions) { + PrintActions(Actions); + exit(0); + } + assert(0 && "FIXME: Implement"); return new Compilation(); } -void Driver::PrintOptions(const ArgList *Args) { +void Driver::PrintOptions(const ArgList &Args) { unsigned i = 0; - for (ArgList::const_iterator it = Args->begin(), ie = Args->end(); + for (ArgList::const_iterator it = Args.begin(), ie = Args.end(); it != ie; ++it, ++i) { Arg *A = *it; llvm::errs() << "Option " << i << " - " @@ -135,12 +158,112 @@ void Driver::PrintOptions(const ArgList *Args) { for (unsigned j = 0; j < A->getNumValues(); ++j) { if (j) llvm::errs() << ", "; - llvm::errs() << '"' << A->getValue(*Args, j) << '"'; + llvm::errs() << '"' << A->getValue(Args, j) << '"'; } llvm::errs() << "}\n"; } } +void Driver::PrintActions(const llvm::SmallVector &Actions) { + llvm::errs() << "FIXME: Print actions."; +} + +void Driver::BuildUniversalActions(const ArgList &Args, + llvm::SmallVector &Actions) { + // FIXME: Implement + BuildActions(Args, Actions); +} + +void Driver::BuildActions(const ArgList &Args, + llvm::SmallVector &Actions) { + types::ID InputType = types::TY_INVALID; + Arg *InputTypeArg = 0; + + llvm::SmallVector, 16> Inputs; + for (ArgList::const_iterator it = Args.begin(), ie = Args.end(); + it != ie; ++it) { + Arg *A = *it; + + if (isa(A->getOption())) { + const char *Value = A->getValue(Args); + types::ID Ty = types::TY_INVALID; + + // Infer the input type if necessary. + if (!InputType) { + // stdin must be handled specially. + if (memcmp(Value, "-", 2) == 0) { + // If running with -E, treat as a C input (this changes the + // builtin macros, for example). This may be overridden by + // -ObjC below. + // + // Otherwise emit an error but still use a valid type to + // avoid spurious errors (e.g., no inputs). + if (!Args.hasArg(options::OPT_E)) + Diag("-E or -x required when input is from standard input"); + Ty = types::TY_C; + } else { + // Otherwise lookup by extension, and fallback to ObjectType + // if not found. + if (const char *Ext = strrchr(Value, '.')) + Ty = types::lookupTypeForExtension(Ext + 1); + if (Ty == types::TY_INVALID) + Ty = types::TY_Object; + } + + // -ObjC and -ObjC++ override the default language, but only + // -for "source files". We just treat everything that isn't a + // -linker input as a source file. + // + // FIXME: Clean this up if we move the phase sequence into the + // type. + if (Ty != types::TY_Object) { + if (Args.hasArg(options::OPT_ObjC)) + Ty = types::TY_ObjC; + else if (Args.hasArg(options::OPT_ObjCXX)) + Ty = types::TY_ObjCXX; + } + } else { + assert(InputTypeArg && "InputType set w/o InputTypeArg"); + InputTypeArg->claim(); + Ty = InputType; + } + + // Check that the file exists. It isn't clear this is worth + // doing, since the tool presumably does this anyway, and this + // just adds an extra stat to the equation, but this is gcc + // compatible. + if (memcmp(Value, "-", 2) != 0 && !llvm::sys::Path(Value).exists()) + Diag("no such file or directory: ") << A->getValue(Args) << "\n"; + else + Inputs.push_back(std::make_pair(Ty, A)); + + } else if (A->getOption().isLinkerInput()) { + // Just treat as object type, we could make a special type for + // this if necessary. + Inputs.push_back(std::make_pair(types::TY_Object, A)); + + } else if (A->getOption().getId() == options::OPT_x) { + InputTypeArg = A; + InputType = types::lookupTypeForTypeSpecifier(A->getValue(Args)); + + // Follow gcc behavior and treat as linker input for invalid -x + // options. Its not clear why we shouldn't just revert to + // unknown; but this isn't very important, we might as well be + // bug comatible. + if (!InputType) { + Diag("language not recognized: ") << A->getValue(Args) << "\n"; + InputType = types::TY_Object; + } + } + } + + for (unsigned i = 0, e = Inputs.size(); i != e; ++i) { + llvm::errs() << "input " << i << ": " + << Inputs[i].second->getValue(Args) << "\n"; + } + exit(0); +} + HostInfo *Driver::GetHostInfo(const char *Triple) { // Dice into arch, platform, and OS. This matches // arch,platform,os = '(.*?)-(.*?)-(.*?)' @@ -163,3 +286,8 @@ HostInfo *Driver::GetHostInfo(const char *Triple) { return new UnknownHostInfo(Arch.c_str(), Platform.c_str(), OS.c_str()); } + +// FIXME: Migrate to a normal diagnostics client. +llvm::raw_ostream &Driver::Diag(const char *Message) const { + return (llvm::errs() << Message); +}