diff options
author | rdivacky <rdivacky@FreeBSD.org> | 2009-10-14 18:03:49 +0000 |
---|---|---|
committer | rdivacky <rdivacky@FreeBSD.org> | 2009-10-14 18:03:49 +0000 |
commit | 9092c3e0fa01f3139b016d05d267a89e3b07747a (patch) | |
tree | 137ebebcae16fb0ce7ab4af456992bbd8d22fced /lib/Driver | |
parent | 4981926bf654fe5a2c3893f24ca44106b217e71e (diff) | |
download | FreeBSD-src-9092c3e0fa01f3139b016d05d267a89e3b07747a.zip FreeBSD-src-9092c3e0fa01f3139b016d05d267a89e3b07747a.tar.gz |
Update clang to r84119.
Diffstat (limited to 'lib/Driver')
-rw-r--r-- | lib/Driver/Action.cpp | 12 | ||||
-rw-r--r-- | lib/Driver/Arg.cpp | 23 | ||||
-rw-r--r-- | lib/Driver/ArgList.cpp | 54 | ||||
-rw-r--r-- | lib/Driver/Compilation.cpp | 46 | ||||
-rw-r--r-- | lib/Driver/Driver.cpp | 580 | ||||
-rw-r--r-- | lib/Driver/HostInfo.cpp | 257 | ||||
-rw-r--r-- | lib/Driver/Job.cpp | 6 | ||||
-rw-r--r-- | lib/Driver/Makefile | 16 | ||||
-rw-r--r-- | lib/Driver/OptTable.cpp | 18 | ||||
-rw-r--r-- | lib/Driver/Option.cpp | 57 | ||||
-rw-r--r-- | lib/Driver/Tool.cpp | 2 | ||||
-rw-r--r-- | lib/Driver/ToolChain.cpp | 12 | ||||
-rw-r--r-- | lib/Driver/ToolChains.cpp | 392 | ||||
-rw-r--r-- | lib/Driver/ToolChains.h | 138 | ||||
-rw-r--r-- | lib/Driver/Tools.cpp | 1082 | ||||
-rw-r--r-- | lib/Driver/Tools.h | 174 | ||||
-rw-r--r-- | lib/Driver/Types.cpp | 48 |
17 files changed, 1929 insertions, 988 deletions
diff --git a/lib/Driver/Action.cpp b/lib/Driver/Action.cpp index cabc33e..6243489 100644 --- a/lib/Driver/Action.cpp +++ b/lib/Driver/Action.cpp @@ -29,16 +29,16 @@ const char *Action::getClassName(ActionClass AC) { case LinkJobClass: return "linker"; case LipoJobClass: return "lipo"; } - + assert(0 && "invalid class"); return 0; } -InputAction::InputAction(const Arg &_Input, types::ID _Type) +InputAction::InputAction(const Arg &_Input, types::ID _Type) : Action(InputClass, _Type), Input(_Input) { } -BindArchAction::BindArchAction(Action *Input, const char *_ArchName) +BindArchAction::BindArchAction(Action *Input, const char *_ArchName) : Action(BindArchClass, Input, Input->getType()), ArchName(_ArchName) { } @@ -46,7 +46,7 @@ JobAction::JobAction(ActionClass Kind, Action *Input, types::ID Type) : Action(Kind, Input, Type) { } -JobAction::JobAction(ActionClass Kind, const ActionList &Inputs, types::ID Type) +JobAction::JobAction(ActionClass Kind, const ActionList &Inputs, types::ID Type) : Action(Kind, Inputs, Type) { } @@ -70,10 +70,10 @@ AssembleJobAction::AssembleJobAction(Action *Input, types::ID OutputType) : JobAction(AssembleJobClass, Input, OutputType) { } -LinkJobAction::LinkJobAction(ActionList &Inputs, types::ID Type) +LinkJobAction::LinkJobAction(ActionList &Inputs, types::ID Type) : JobAction(LinkJobClass, Inputs, Type) { } -LipoJobAction::LipoJobAction(ActionList &Inputs, types::ID Type) +LipoJobAction::LipoJobAction(ActionList &Inputs, types::ID Type) : JobAction(LipoJobClass, Inputs, Type) { } diff --git a/lib/Driver/Arg.cpp b/lib/Driver/Arg.cpp index e227d7e..a09ba09 100644 --- a/lib/Driver/Arg.cpp +++ b/lib/Driver/Arg.cpp @@ -14,10 +14,9 @@ using namespace clang::driver; -Arg::Arg(ArgClass _Kind, const Option *_Opt, unsigned _Index, - const Arg *_BaseArg) - : Kind(_Kind), Opt(_Opt), BaseArg(_BaseArg), Index(_Index), Claimed(false) -{ +Arg::Arg(ArgClass _Kind, const Option *_Opt, unsigned _Index, + const Arg *_BaseArg) + : Kind(_Kind), Opt(_Opt), BaseArg(_BaseArg), Index(_Index), Claimed(false) { } Arg::~Arg() { } @@ -54,7 +53,7 @@ std::string Arg::getAsString(const ArgList &Args) const { ArgStringList ASL; render(Args, ASL); - for (ArgStringList::iterator + for (ArgStringList::iterator it = ASL.begin(), ie = ASL.end(); it != ie; ++it) { if (it != ASL.begin()) OS << ' '; @@ -87,7 +86,7 @@ const char *FlagArg::getValue(const ArgList &Args, unsigned N) const { return 0; } -PositionalArg::PositionalArg(const Option *Opt, unsigned Index, +PositionalArg::PositionalArg(const Option *Opt, unsigned Index, const Arg *BaseArg) : Arg(PositionalClass, Opt, Index, BaseArg) { } @@ -120,10 +119,10 @@ const char *JoinedArg::getValue(const ArgList &Args, unsigned N) const { return Args.getArgString(getIndex()) + strlen(getOption().getName()); } -CommaJoinedArg::CommaJoinedArg(const Option *Opt, unsigned Index, +CommaJoinedArg::CommaJoinedArg(const Option *Opt, unsigned Index, const char *Str, const Arg *BaseArg) : Arg(CommaJoinedClass, Opt, Index, BaseArg) { - const char *Prev = Str; + const char *Prev = Str; for (;; ++Str) { char c = *Str; @@ -167,23 +166,23 @@ void SeparateArg::render(const ArgList &Args, ArgStringList &Output) const { } } -const char *SeparateArg::getValue(const ArgList &Args, unsigned N) const { +const char *SeparateArg::getValue(const ArgList &Args, unsigned N) const { assert(N < getNumValues() && "Invalid index."); return Args.getArgString(getIndex() + 1 + N); } -JoinedAndSeparateArg::JoinedAndSeparateArg(const Option *Opt, unsigned Index, +JoinedAndSeparateArg::JoinedAndSeparateArg(const Option *Opt, unsigned Index, const Arg *BaseArg) : Arg(JoinedAndSeparateClass, Opt, Index, BaseArg) { } -void JoinedAndSeparateArg::render(const ArgList &Args, +void JoinedAndSeparateArg::render(const ArgList &Args, ArgStringList &Output) const { Output.push_back(Args.getArgString(getIndex())); Output.push_back(Args.getArgString(getIndex() + 1)); } -const char *JoinedAndSeparateArg::getValue(const ArgList &Args, +const char *JoinedAndSeparateArg::getValue(const ArgList &Args, unsigned N) const { assert(N < getNumValues() && "Invalid index."); if (N == 0) diff --git a/lib/Driver/ArgList.cpp b/lib/Driver/ArgList.cpp index 54dd4bb..8d2138d 100644 --- a/lib/Driver/ArgList.cpp +++ b/lib/Driver/ArgList.cpp @@ -11,6 +11,10 @@ #include "clang/Driver/Arg.h" #include "clang/Driver/Option.h" +#include "llvm/ADT/SmallString.h" +#include "llvm/ADT/Twine.h" +#include "llvm/Support/raw_ostream.h" + using namespace clang::driver; ArgList::ArgList(arglist_type &_Args) : Args(_Args) { @@ -31,13 +35,13 @@ Arg *ArgList::getLastArg(options::ID Id, bool Claim) const { return *it; } } - + return 0; } Arg *ArgList::getLastArg(options::ID Id0, options::ID Id1, bool Claim) const { Arg *Res, *A0 = getLastArg(Id0, false), *A1 = getLastArg(Id1, false); - + if (A0 && A1) Res = A0->getIndex() > A1->getIndex() ? A0 : A1; else @@ -102,7 +106,7 @@ void ArgList::AddAllArgs(ArgStringList &Output, options::ID Id0) const { } } -void ArgList::AddAllArgs(ArgStringList &Output, options::ID Id0, +void ArgList::AddAllArgs(ArgStringList &Output, options::ID Id0, options::ID Id1) const { // FIXME: Make fast. for (const_iterator it = begin(), ie = end(); it != ie; ++it) { @@ -114,7 +118,7 @@ void ArgList::AddAllArgs(ArgStringList &Output, options::ID Id0, } } -void ArgList::AddAllArgs(ArgStringList &Output, options::ID Id0, +void ArgList::AddAllArgs(ArgStringList &Output, options::ID Id0, options::ID Id1, options::ID Id2) const { // FIXME: Make fast. for (const_iterator it = begin(), ie = end(); it != ie; ++it) { @@ -139,7 +143,7 @@ void ArgList::AddAllArgValues(ArgStringList &Output, options::ID Id0) const { } } -void ArgList::AddAllArgValues(ArgStringList &Output, options::ID Id0, +void ArgList::AddAllArgValues(ArgStringList &Output, options::ID Id0, options::ID Id1) const { // FIXME: Make fast. for (const_iterator it = begin(), ie = end(); it != ie; ++it) { @@ -182,11 +186,16 @@ void ArgList::ClaimAllArgs(options::ID Id0) const { } } +const char *ArgList::MakeArgString(const llvm::Twine &T) const { + llvm::SmallString<256> Str; + T.toVector(Str); + return MakeArgString(Str.str()); +} + // -InputArgList::InputArgList(const char **ArgBegin, const char **ArgEnd) - : ArgList(ActualArgs), NumInputArgStrings(ArgEnd - ArgBegin) -{ +InputArgList::InputArgList(const char **ArgBegin, const char **ArgEnd) + : ArgList(ActualArgs), NumInputArgStrings(ArgEnd - ArgBegin) { ArgStrings.append(ArgBegin, ArgEnd); } @@ -196,7 +205,7 @@ InputArgList::~InputArgList() { delete *it; } -unsigned InputArgList::MakeIndex(const char *String0) const { +unsigned InputArgList::MakeIndex(llvm::StringRef String0) const { unsigned Index = ArgStrings.size(); // Tuck away so we have a reliable const char *. @@ -206,8 +215,8 @@ unsigned InputArgList::MakeIndex(const char *String0) const { return Index; } -unsigned InputArgList::MakeIndex(const char *String0, - const char *String1) const { +unsigned InputArgList::MakeIndex(llvm::StringRef String0, + llvm::StringRef String1) const { unsigned Index0 = MakeIndex(String0); unsigned Index1 = MakeIndex(String1); assert(Index0 + 1 == Index1 && "Unexpected non-consecutive indices!"); @@ -215,7 +224,7 @@ unsigned InputArgList::MakeIndex(const char *String0, return Index0; } -const char *InputArgList::MakeArgString(const char *Str) const { +const char *InputArgList::MakeArgString(llvm::StringRef Str) const { return getArgString(MakeIndex(Str)); } @@ -223,18 +232,17 @@ const char *InputArgList::MakeArgString(const char *Str) const { DerivedArgList::DerivedArgList(InputArgList &_BaseArgs, bool _OnlyProxy) : ArgList(_OnlyProxy ? _BaseArgs.getArgs() : ActualArgs), - BaseArgs(_BaseArgs), OnlyProxy(_OnlyProxy) -{ + BaseArgs(_BaseArgs), OnlyProxy(_OnlyProxy) { } DerivedArgList::~DerivedArgList() { // We only own the arguments we explicitly synthesized. - for (iterator it = SynthesizedArgs.begin(), ie = SynthesizedArgs.end(); + for (iterator it = SynthesizedArgs.begin(), ie = SynthesizedArgs.end(); it != ie; ++it) delete *it; } -const char *DerivedArgList::MakeArgString(const char *Str) const { +const char *DerivedArgList::MakeArgString(llvm::StringRef Str) const { return BaseArgs.MakeArgString(Str); } @@ -242,19 +250,19 @@ Arg *DerivedArgList::MakeFlagArg(const Arg *BaseArg, const Option *Opt) const { return new FlagArg(Opt, BaseArgs.MakeIndex(Opt->getName()), BaseArg); } -Arg *DerivedArgList::MakePositionalArg(const Arg *BaseArg, const Option *Opt, - const char *Value) const { +Arg *DerivedArgList::MakePositionalArg(const Arg *BaseArg, const Option *Opt, + llvm::StringRef Value) const { return new PositionalArg(Opt, BaseArgs.MakeIndex(Value), BaseArg); } -Arg *DerivedArgList::MakeSeparateArg(const Arg *BaseArg, const Option *Opt, - const char *Value) const { - return new SeparateArg(Opt, BaseArgs.MakeIndex(Opt->getName(), Value), 1, +Arg *DerivedArgList::MakeSeparateArg(const Arg *BaseArg, const Option *Opt, + llvm::StringRef Value) const { + return new SeparateArg(Opt, BaseArgs.MakeIndex(Opt->getName(), Value), 1, BaseArg); } -Arg *DerivedArgList::MakeJoinedArg(const Arg *BaseArg, const Option *Opt, - const char *Value) const { +Arg *DerivedArgList::MakeJoinedArg(const Arg *BaseArg, const Option *Opt, + llvm::StringRef Value) const { std::string Joined(Opt->getName()); Joined += Value; return new JoinedArg(Opt, BaseArgs.MakeIndex(Joined.c_str()), BaseArg); diff --git a/lib/Driver/Compilation.cpp b/lib/Driver/Compilation.cpp index 7e29b67..c12f5aa 100644 --- a/lib/Driver/Compilation.cpp +++ b/lib/Driver/Compilation.cpp @@ -23,36 +23,38 @@ using namespace clang::driver; Compilation::Compilation(const Driver &D, const ToolChain &_DefaultToolChain, - InputArgList *_Args) + InputArgList *_Args) : TheDriver(D), DefaultToolChain(_DefaultToolChain), Args(_Args) { } -Compilation::~Compilation() { +Compilation::~Compilation() { delete Args; - + // Free any derived arg lists. - for (llvm::DenseMap<const ToolChain*, DerivedArgList*>::iterator - it = TCArgs.begin(), ie = TCArgs.end(); it != ie; ++it) + for (llvm::DenseMap<std::pair<const ToolChain*, const char*>, + DerivedArgList*>::iterator it = TCArgs.begin(), + ie = TCArgs.end(); it != ie; ++it) delete it->second; // Free the actions, if built. - for (ActionList::iterator it = Actions.begin(), ie = Actions.end(); + for (ActionList::iterator it = Actions.begin(), ie = Actions.end(); it != ie; ++it) delete *it; } -const DerivedArgList &Compilation::getArgsForToolChain(const ToolChain *TC) { +const DerivedArgList &Compilation::getArgsForToolChain(const ToolChain *TC, + const char *BoundArch) { if (!TC) TC = &DefaultToolChain; - DerivedArgList *&Entry = TCArgs[TC]; + DerivedArgList *&Entry = TCArgs[std::make_pair(TC, BoundArch)]; if (!Entry) - Entry = TC->TranslateArgs(*Args); + Entry = TC->TranslateArgs(*Args, BoundArch); return *Entry; } -void Compilation::PrintJob(llvm::raw_ostream &OS, const Job &J, +void Compilation::PrintJob(llvm::raw_ostream &OS, const Job &J, const char *Terminator, bool Quote) const { if (const Command *C = dyn_cast<Command>(&J)) { OS << " \"" << C->getExecutable() << '"'; @@ -65,22 +67,22 @@ void Compilation::PrintJob(llvm::raw_ostream &OS, const Job &J, } OS << Terminator; } else if (const PipedJob *PJ = dyn_cast<PipedJob>(&J)) { - for (PipedJob::const_iterator + for (PipedJob::const_iterator it = PJ->begin(), ie = PJ->end(); it != ie; ++it) PrintJob(OS, **it, (it + 1 != PJ->end()) ? " |\n" : "\n", Quote); } else { const JobList *Jobs = cast<JobList>(&J); - for (JobList::const_iterator + for (JobList::const_iterator it = Jobs->begin(), ie = Jobs->end(); it != ie; ++it) PrintJob(OS, **it, Terminator, Quote); } } -bool Compilation::CleanupFileList(const ArgStringList &Files, +bool Compilation::CleanupFileList(const ArgStringList &Files, bool IssueErrors) const { bool Success = true; - for (ArgStringList::const_iterator + for (ArgStringList::const_iterator it = Files.begin(), ie = Files.end(); it != ie; ++it) { llvm::sys::Path P(*it); std::string Error; @@ -92,7 +94,7 @@ bool Compilation::CleanupFileList(const ArgStringList &Files, // FIXME: Grumble, P.exists() is broken. PR3837. struct stat buf; - if (::stat(P.c_str(), &buf) == 0 + if (::stat(P.c_str(), &buf) == 0 || errno != ENOENT) { if (IssueErrors) getDriver().Diag(clang::diag::err_drv_unable_to_remove_file) @@ -112,12 +114,12 @@ int Compilation::ExecuteCommand(const Command &C, Argv[0] = C.getExecutable(); std::copy(C.getArguments().begin(), C.getArguments().end(), Argv+1); Argv[C.getArguments().size() + 1] = 0; - + if (getDriver().CCCEcho || getArgs().hasArg(options::OPT_v)) PrintJob(llvm::errs(), C, "\n", false); - + std::string Error; - int Res = + int Res = llvm::sys::Program::ExecuteAndWait(Prog, Argv, /*env*/0, /*redirects*/0, /*secondsToWait*/0, /*memoryLimit*/0, @@ -126,7 +128,7 @@ int Compilation::ExecuteCommand(const Command &C, assert(Res && "Error string set with 0 result code!"); getDriver().Diag(clang::diag::err_drv_command_failure) << Error; } - + if (Res) FailingCommand = &C; @@ -134,7 +136,7 @@ int Compilation::ExecuteCommand(const Command &C, return Res; } -int Compilation::ExecuteJob(const Job &J, +int Compilation::ExecuteJob(const Job &J, const Command *&FailingCommand) const { if (const Command *C = dyn_cast<Command>(&J)) { return ExecuteCommand(*C, FailingCommand); @@ -142,13 +144,13 @@ int Compilation::ExecuteJob(const Job &J, // Piped commands with a single job are easy. if (PJ->size() == 1) return ExecuteCommand(**PJ->begin(), FailingCommand); - + FailingCommand = *PJ->begin(); getDriver().Diag(clang::diag::err_drv_unsupported_opt) << "-pipe"; return 1; } else { const JobList *Jobs = cast<JobList>(&J); - for (JobList::const_iterator + for (JobList::const_iterator it = Jobs->begin(), ie = Jobs->end(); it != ie; ++it) if (int Res = ExecuteJob(**it, FailingCommand)) return Res; diff --git a/lib/Driver/Driver.cpp b/lib/Driver/Driver.cpp index 1b0b561..b4693f2 100644 --- a/lib/Driver/Driver.cpp +++ b/lib/Driver/Driver.cpp @@ -37,22 +37,34 @@ using namespace clang::driver; using namespace clang; +// Used to set values for "production" clang, for releases. +// #define USE_PRODUCTION_CLANG + Driver::Driver(const char *_Name, const char *_Dir, const char *_DefaultHostTriple, const char *_DefaultImageName, - Diagnostic &_Diags) - : Opts(new OptTable()), Diags(_Diags), + bool IsProduction, Diagnostic &_Diags) + : Opts(new OptTable()), Diags(_Diags), Name(_Name), Dir(_Dir), DefaultHostTriple(_DefaultHostTriple), DefaultImageName(_DefaultImageName), Host(0), CCCIsCXX(false), CCCEcho(false), CCCPrintBindings(false), - CCCGenericGCCName("gcc"), CCCUseClang(true), CCCUseClangCXX(false), - CCCUseClangCPP(true), CCCUsePCH(true), - SuppressMissingInputWarning(false) -{ - // Only use clang on i386 and x86_64 by default. - CCCClangArchs.insert("i386"); - CCCClangArchs.insert("x86_64"); + CCCGenericGCCName("gcc"), CCCUseClang(true), + CCCUseClangCXX(true), CCCUseClangCPP(true), CCCUsePCH(true), + SuppressMissingInputWarning(false) { + if (IsProduction) { + // In a "production" build, only use clang on architectures we expect to + // work, and don't use clang C++. + // + // During development its more convenient to always have the driver use + // clang, but we don't want users to be confused when things don't work, or + // to file bugs for things we don't support. + CCCClangArchs.insert(llvm::Triple::x86); + CCCClangArchs.insert(llvm::Triple::x86_64); + CCCClangArchs.insert(llvm::Triple::arm); + + CCCUseClangCXX = false; + } } Driver::~Driver() { @@ -60,20 +72,20 @@ Driver::~Driver() { delete Host; } -InputArgList *Driver::ParseArgStrings(const char **ArgBegin, +InputArgList *Driver::ParseArgStrings(const char **ArgBegin, const char **ArgEnd) { llvm::PrettyStackTraceString CrashInfo("Command line argument parsing"); InputArgList *Args = new InputArgList(ArgBegin, ArgEnd); - + // FIXME: Handle '@' args (or at least error on them). unsigned Index = 0, End = ArgEnd - ArgBegin; while (Index < End) { - // gcc's handling of empty arguments doesn't make - // sense, but this is not a common use case. :) + // gcc's handling of empty arguments doesn't make sense, but this is not a + // common use case. :) // - // We just ignore them here (note that other things may - // still take them as arguments). + // We just ignore them here (note that other things may still take them as + // arguments). if (Args->getArgString(Index)[0] == '\0') { ++Index; continue; @@ -105,28 +117,27 @@ InputArgList *Driver::ParseArgStrings(const char **ArgBegin, Compilation *Driver::BuildCompilation(int argc, const char **argv) { llvm::PrettyStackTraceString CrashInfo("Compilation construction"); - // FIXME: Handle environment options which effect driver behavior, - // somewhere (client?). GCC_EXEC_PREFIX, COMPILER_PATH, - // LIBRARY_PATH, LPATH, CC_PRINT_OPTIONS, QA_OVERRIDE_GCC3_OPTIONS. + // FIXME: Handle environment options which effect driver behavior, somewhere + // (client?). GCC_EXEC_PREFIX, COMPILER_PATH, LIBRARY_PATH, LPATH, + // CC_PRINT_OPTIONS. // FIXME: What are we going to do with -V and -b? - // FIXME: This stuff needs to go into the Compilation, not the - // driver. + // FIXME: This stuff needs to go into the Compilation, not the driver. bool CCCPrintOptions = false, CCCPrintActions = false; const char **Start = argv + 1, **End = argv + argc; const char *HostTriple = DefaultHostTriple.c_str(); - // Read -ccc args. + // Read -ccc args. // - // FIXME: We need to figure out where this behavior should - // live. Most of it should be outside in the client; the parts that - // aren't should have proper options, either by introducing new ones - // or by overloading gcc ones like -V or -b. + // FIXME: We need to figure out where this behavior should live. Most of it + // should be outside in the client; the parts that aren't should have proper + // options, either by introducing new ones or by overloading gcc ones like -V + // or -b. for (; Start != End && memcmp(*Start, "-ccc-", 5) == 0; ++Start) { const char *Opt = *Start + 5; - + if (!strcmp(Opt, "print-options")) { CCCPrintOptions = true; } else if (!strcmp(Opt, "print-phases")) { @@ -137,13 +148,15 @@ Compilation *Driver::BuildCompilation(int argc, const char **argv) { CCCIsCXX = true; } else if (!strcmp(Opt, "echo")) { CCCEcho = true; - + } else if (!strcmp(Opt, "gcc-name")) { assert(Start+1 < End && "FIXME: -ccc- argument handling."); CCCGenericGCCName = *++Start; } else if (!strcmp(Opt, "clang-cxx")) { CCCUseClangCXX = true; + } else if (!strcmp(Opt, "no-clang-cxx")) { + CCCUseClangCXX = false; } else if (!strcmp(Opt, "pch-is-pch")) { CCCUsePCH = true; } else if (!strcmp(Opt, "pch-is-pth")) { @@ -154,27 +167,35 @@ Compilation *Driver::BuildCompilation(int argc, const char **argv) { CCCUseClangCPP = false; } else if (!strcmp(Opt, "clang-archs")) { assert(Start+1 < End && "FIXME: -ccc- argument handling."); - const char *Cur = *++Start; - + llvm::StringRef Cur = *++Start; + CCCClangArchs.clear(); - for (;;) { - const char *Next = strchr(Cur, ','); + while (!Cur.empty()) { + std::pair<llvm::StringRef, llvm::StringRef> Split = Cur.split(','); - if (Next) { - if (Cur != Next) - CCCClangArchs.insert(std::string(Cur, Next)); - Cur = Next + 1; - } else { - if (*Cur != '\0') - CCCClangArchs.insert(std::string(Cur)); - break; + if (!Split.first.empty()) { + llvm::Triple::ArchType Arch = + llvm::Triple(Split.first, "", "").getArch(); + + if (Arch == llvm::Triple::UnknownArch) { + // FIXME: Error handling. + llvm::errs() << "invalid arch name: " << Split.first << "\n"; + exit(1); + } + + CCCClangArchs.insert(Arch); } - } + Cur = Split.second; + } } else if (!strcmp(Opt, "host-triple")) { assert(Start+1 < End && "FIXME: -ccc- argument handling."); HostTriple = *++Start; + } else if (!strcmp(Opt, "install-dir")) { + assert(Start+1 < End && "FIXME: -ccc- argument handling."); + Dir = *++Start; + } else { // FIXME: Error handling. llvm::errs() << "invalid option: " << *Start << "\n"; @@ -187,7 +208,7 @@ Compilation *Driver::BuildCompilation(int argc, const char **argv) { Host = GetHostInfo(HostTriple); // The compilation takes ownership of Args. - Compilation *C = new Compilation(*this, *Host->getToolChain(*Args), Args); + Compilation *C = new Compilation(*this, *Host->CreateToolChain(*Args), Args); // FIXME: This behavior shouldn't be here. if (CCCPrintOptions) { @@ -198,10 +219,10 @@ Compilation *Driver::BuildCompilation(int argc, const char **argv) { if (!HandleImmediateArgs(*C)) return C; - // Construct the list of abstract actions to perform for this - // compilation. We avoid passing a Compilation here simply to - // enforce the abstraction that pipelining is not host or toolchain - // dependent (other than the driver driver test). + // Construct the list of abstract actions to perform for this compilation. We + // avoid passing a Compilation here simply to enforce the abstraction that + // pipelining is not host or toolchain dependent (other than the driver driver + // test). if (Host->useDriverDriver()) BuildUniversalActions(C->getArgs(), C->getActions()); else @@ -230,7 +251,7 @@ int Driver::ExecuteCompilation(const Compilation &C) const { const Command *FailingCommand = 0; int Res = C.ExecuteJob(C.getJobs(), FailingCommand); - + // Remove temp files. C.CleanupFileList(C.getTempFiles()); @@ -254,10 +275,10 @@ int Driver::ExecuteCompilation(const Compilation &C) const { if (!IsFriendlyTool || Res != 1) { // FIXME: See FIXME above regarding result code interpretation. if (Res < 0) - Diag(clang::diag::err_drv_command_signalled) + Diag(clang::diag::err_drv_command_signalled) << Source.getClassName() << -Res; else - Diag(clang::diag::err_drv_command_failed) + Diag(clang::diag::err_drv_command_failed) << Source.getClassName() << Res; } } @@ -267,7 +288,7 @@ int Driver::ExecuteCompilation(const Compilation &C) const { void Driver::PrintOptions(const ArgList &Args) const { 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 << " - " @@ -284,10 +305,10 @@ void Driver::PrintOptions(const ArgList &Args) const { static std::string getOptionHelpName(const OptTable &Opts, options::ID Id) { std::string Name = Opts.getOptionName(Id); - + // Add metavar, if used. switch (Opts.getOptionKind(Id)) { - case Option::GroupClass: case Option::InputClass: case Option::UnknownClass: + case Option::GroupClass: case Option::InputClass: case Option::UnknownClass: assert(0 && "Invalid option with help text."); case Option::MultiArgClass: case Option::JoinedAndSeparateClass: @@ -333,11 +354,13 @@ void Driver::PrintHelp(bool ShowHidden) const { OptionHelp.push_back(std::make_pair("-ccc-gcc-name", "Name for native GCC compiler")); OptionHelp.push_back(std::make_pair("-ccc-clang-cxx", - "Use the clang compiler for C++")); + "Enable the clang compiler for C++")); + OptionHelp.push_back(std::make_pair("-ccc-no-clang-cxx", + "Disable the clang compiler for C++")); OptionHelp.push_back(std::make_pair("-ccc-no-clang", - "Never use the clang compiler")); + "Disable the clang compiler")); OptionHelp.push_back(std::make_pair("-ccc-no-clang-cpp", - "Never use the clang preprocessor")); + "Disable the clang preprocessor")); OptionHelp.push_back(std::make_pair("-ccc-clang-archs", "Comma separate list of architectures " "to use the clang compiler for")); @@ -348,7 +371,9 @@ void Driver::PrintHelp(bool ShowHidden) const { OptionHelp.push_back(std::make_pair("\nDEBUG/DEVELOPMENT OPTIONS:","")); OptionHelp.push_back(std::make_pair("-ccc-host-triple", - "Simulate running on the given target")); + "Simulate running on the given target")); + OptionHelp.push_back(std::make_pair("-ccc-install-dir", + "Simulate installation in the given directory")); OptionHelp.push_back(std::make_pair("-ccc-print-options", "Dump parsed command line arguments")); OptionHelp.push_back(std::make_pair("-ccc-print-phases", @@ -360,15 +385,14 @@ void Driver::PrintHelp(bool ShowHidden) const { "arguments to prepend to the command line")); } - // Find the maximum option length. + // Find the maximum option length. unsigned OptionFieldWidth = 0; for (unsigned i = 0, e = OptionHelp.size(); i != e; ++i) { // Skip titles. if (!OptionHelp[i].second) continue; - // Limit the amount of padding we are willing to give up for - // alignment. + // Limit the amount of padding we are willing to give up for alignment. unsigned Length = OptionHelp[i].first.size(); if (Length <= 23) OptionFieldWidth = std::max(OptionFieldWidth, Length); @@ -385,60 +409,51 @@ void Driver::PrintHelp(bool ShowHidden) const { OS.flush(); } -void Driver::PrintVersion(const Compilation &C) const { - static char buf[] = "$URL: https://ed@llvm.org/svn/llvm-project/cfe/trunk/lib/Driver/Driver.cpp $"; - char *zap = strstr(buf, "/lib/Driver"); - if (zap) - *zap = 0; - zap = strstr(buf, "/clang/tools/clang"); - if (zap) - *zap = 0; - const char *vers = buf+6; - // FIXME: Add cmake support and remove #ifdef -#ifdef SVN_REVISION - const char *revision = SVN_REVISION; -#else - const char *revision = ""; +void Driver::PrintVersion(const Compilation &C, llvm::raw_ostream &OS) const { + // FIXME: The following handlers should use a callback mechanism, we don't + // know what the client would like to do. +#ifdef CLANG_VENDOR + OS << CLANG_VENDOR; #endif - // FIXME: The following handlers should use a callback mechanism, we - // don't know what the client would like to do. - - llvm::errs() << "clang version " CLANG_VERSION_STRING " (" - << vers << " " << revision << ")" << '\n'; + OS << "clang version " CLANG_VERSION_STRING " (" + << getClangSubversionPath(); + if (unsigned Revision = getClangSubversionRevision()) + OS << " " << Revision; + OS << ")" << '\n'; const ToolChain &TC = C.getDefaultToolChain(); - llvm::errs() << "Target: " << TC.getTripleString() << '\n'; + OS << "Target: " << TC.getTripleString() << '\n'; // Print the threading model. // // FIXME: Implement correctly. - llvm::errs() << "Thread model: " << "posix" << '\n'; + OS << "Thread model: " << "posix" << '\n'; } bool Driver::HandleImmediateArgs(const Compilation &C) { - // The order these options are handled in in gcc is all over the - // place, but we don't expect inconsistencies w.r.t. that to matter - // in practice. + // The order these options are handled in in gcc is all over the place, but we + // don't expect inconsistencies w.r.t. that to matter in practice. if (C.getArgs().hasArg(options::OPT_dumpversion)) { llvm::outs() << CLANG_VERSION_STRING "\n"; return false; } - if (C.getArgs().hasArg(options::OPT__help) || + if (C.getArgs().hasArg(options::OPT__help) || C.getArgs().hasArg(options::OPT__help_hidden)) { PrintHelp(C.getArgs().hasArg(options::OPT__help_hidden)); return false; } if (C.getArgs().hasArg(options::OPT__version)) { - PrintVersion(C); + // Follow gcc behavior and use stdout for --version and stderr for -v. + PrintVersion(C, llvm::outs()); return false; } - if (C.getArgs().hasArg(options::OPT_v) || + if (C.getArgs().hasArg(options::OPT_v) || C.getArgs().hasArg(options::OPT__HASH_HASH_HASH)) { - PrintVersion(C); + PrintVersion(C, llvm::errs()); SuppressMissingInputWarning = true; } @@ -453,7 +468,7 @@ bool Driver::HandleImmediateArgs(const Compilation &C) { } llvm::outs() << "\n"; llvm::outs() << "libraries: ="; - for (ToolChain::path_list::const_iterator it = TC.getFilePaths().begin(), + for (ToolChain::path_list::const_iterator it = TC.getFilePaths().begin(), ie = TC.getFilePaths().end(); it != ie; ++it) { if (it != TC.getFilePaths().begin()) llvm::outs() << ':'; @@ -463,22 +478,20 @@ bool Driver::HandleImmediateArgs(const Compilation &C) { return false; } - // FIXME: The following handlers should use a callback mechanism, we - // don't know what the client would like to do. + // FIXME: The following handlers should use a callback mechanism, we don't + // know what the client would like to do. if (Arg *A = C.getArgs().getLastArg(options::OPT_print_file_name_EQ)) { - llvm::outs() << GetFilePath(A->getValue(C.getArgs()), TC).toString() - << "\n"; + llvm::outs() << GetFilePath(A->getValue(C.getArgs()), TC) << "\n"; return false; } if (Arg *A = C.getArgs().getLastArg(options::OPT_print_prog_name_EQ)) { - llvm::outs() << GetProgramPath(A->getValue(C.getArgs()), TC).toString() - << "\n"; + llvm::outs() << GetProgramPath(A->getValue(C.getArgs()), TC) << "\n"; return false; } if (C.getArgs().hasArg(options::OPT_print_libgcc_file_name)) { - llvm::outs() << GetFilePath("libgcc.a", TC).toString() << "\n"; + llvm::outs() << GetFilePath("libgcc.a", TC) << "\n"; return false; } @@ -489,7 +502,7 @@ bool Driver::HandleImmediateArgs(const Compilation &C) { switch (C.getDefaultToolChain().getTriple().getArch()) { default: break; - + case llvm::Triple::x86_64: llvm::outs() << "x86_64;@m64" << "\n"; break; @@ -511,7 +524,7 @@ bool Driver::HandleImmediateArgs(const Compilation &C) { case llvm::Triple::ppc: llvm::outs() << "." << "\n"; break; - + case llvm::Triple::x86_64: llvm::outs() << "x86_64" << "\n"; break; @@ -526,20 +539,19 @@ bool Driver::HandleImmediateArgs(const Compilation &C) { return true; } -static unsigned PrintActions1(const Compilation &C, - Action *A, +static unsigned PrintActions1(const Compilation &C, Action *A, std::map<Action*, unsigned> &Ids) { if (Ids.count(A)) return Ids[A]; - + std::string str; llvm::raw_string_ostream os(str); - + os << Action::getClassName(A->getKind()) << ", "; - if (InputAction *IA = dyn_cast<InputAction>(A)) { + if (InputAction *IA = dyn_cast<InputAction>(A)) { os << "\"" << IA->getInputArg().getValue(C.getArgs()) << "\""; } else if (BindArchAction *BIA = dyn_cast<BindArchAction>(A)) { - os << '"' << (BIA->getArchName() ? BIA->getArchName() : + os << '"' << (BIA->getArchName() ? BIA->getArchName() : C.getDefaultToolChain().getArchName()) << '"' << ", {" << PrintActions1(C, *BIA->begin(), Ids) << "}"; } else { @@ -555,7 +567,7 @@ static unsigned PrintActions1(const Compilation &C, unsigned Id = Ids.size(); Ids[A] = Id; - llvm::errs() << Id << ": " << os.str() << ", " + llvm::errs() << Id << ": " << os.str() << ", " << types::getTypeName(A->getType()) << "\n"; return Id; @@ -563,65 +575,66 @@ static unsigned PrintActions1(const Compilation &C, void Driver::PrintActions(const Compilation &C) const { std::map<Action*, unsigned> Ids; - for (ActionList::const_iterator it = C.getActions().begin(), + for (ActionList::const_iterator it = C.getActions().begin(), ie = C.getActions().end(); it != ie; ++it) PrintActions1(C, *it, Ids); } -void Driver::BuildUniversalActions(const ArgList &Args, +void Driver::BuildUniversalActions(const ArgList &Args, ActionList &Actions) const { - llvm::PrettyStackTraceString CrashInfo("Building actions for universal build"); - // Collect the list of architectures. Duplicates are allowed, but - // should only be handled once (in the order seen). + llvm::PrettyStackTraceString CrashInfo("Building universal build actions"); + // Collect the list of architectures. Duplicates are allowed, but should only + // be handled once (in the order seen). llvm::StringSet<> ArchNames; llvm::SmallVector<const char *, 4> Archs; - for (ArgList::const_iterator it = Args.begin(), ie = Args.end(); + for (ArgList::const_iterator it = Args.begin(), ie = Args.end(); it != ie; ++it) { Arg *A = *it; if (A->getOption().getId() == options::OPT_arch) { - const char *Name = A->getValue(Args); - - // FIXME: We need to handle canonicalization of the specified - // arch? + // Validate the option here; we don't save the type here because its + // particular spelling may participate in other driver choices. + llvm::Triple::ArchType Arch = + llvm::Triple::getArchTypeForDarwinArchName(A->getValue(Args)); + if (Arch == llvm::Triple::UnknownArch) { + Diag(clang::diag::err_drv_invalid_arch_name) + << A->getAsString(Args); + continue; + } A->claim(); - if (ArchNames.insert(Name)) - Archs.push_back(Name); + if (ArchNames.insert(A->getValue(Args))) + Archs.push_back(A->getValue(Args)); } } - // When there is no explicit arch for this platform, make sure we - // still bind the architecture (to the default) so that -Xarch_ is - // handled correctly. + // When there is no explicit arch for this platform, make sure we still bind + // the architecture (to the default) so that -Xarch_ is handled correctly. if (!Archs.size()) Archs.push_back(0); - // FIXME: We killed off some others but these aren't yet detected in - // a functional manner. If we added information to jobs about which - // "auxiliary" files they wrote then we could detect the conflict - // these cause downstream. + // FIXME: We killed off some others but these aren't yet detected in a + // functional manner. If we added information to jobs about which "auxiliary" + // files they wrote then we could detect the conflict these cause downstream. if (Archs.size() > 1) { // No recovery needed, the point of this is just to prevent // overwriting the same files. if (const Arg *A = Args.getLastArg(options::OPT_save_temps)) - Diag(clang::diag::err_drv_invalid_opt_with_multiple_archs) + Diag(clang::diag::err_drv_invalid_opt_with_multiple_archs) << A->getAsString(Args); } ActionList SingleActions; BuildActions(Args, SingleActions); - // Add in arch binding and lipo (if necessary) for every top level - // action. + // Add in arch binding and lipo (if necessary) for every top level action. for (unsigned i = 0, e = SingleActions.size(); i != e; ++i) { Action *Act = SingleActions[i]; - // Make sure we can lipo this kind of output. If not (and it is an - // actual output) then we disallow, since we can't create an - // output file with the right name without overwriting it. We - // could remove this oddity by just changing the output names to - // include the arch, which would also fix + // Make sure we can lipo this kind of output. If not (and it is an actual + // output) then we disallow, since we can't create an output file with the + // right name without overwriting it. We could remove this oddity by just + // changing the output names to include the arch, which would also fix // -save-temps. Compatibility wins for now. if (Archs.size() > 1 && !types::canLipoType(Act->getType())) @@ -632,8 +645,8 @@ void Driver::BuildUniversalActions(const ArgList &Args, for (unsigned i = 0, e = Archs.size(); i != e; ++i) Inputs.push_back(new BindArchAction(Act, Archs[i])); - // Lipo if necessary, We do it this way because we need to set the - // arch flag so that -Xarch_ gets overwritten. + // Lipo if necessary, we do it this way because we need to set the arch flag + // so that -Xarch_ gets overwritten. if (Inputs.size() == 1 || Act->getType() == types::TY_Nothing) Actions.append(Inputs.begin(), Inputs.end()); else @@ -645,15 +658,14 @@ void Driver::BuildActions(const ArgList &Args, ActionList &Actions) const { llvm::PrettyStackTraceString CrashInfo("Building compilation actions"); // Start by constructing the list of inputs and their types. - // Track the current user specified (-x) input. We also explicitly - // track the argument used to set the type; we only want to claim - // the type when we actually use it, so we warn about unused -x - // arguments. + // Track the current user specified (-x) input. We also explicitly track the + // argument used to set the type; we only want to claim the type when we + // actually use it, so we warn about unused -x arguments. types::ID InputType = types::TY_Nothing; Arg *InputTypeArg = 0; llvm::SmallVector<std::pair<types::ID, const Arg*>, 16> Inputs; - for (ArgList::const_iterator it = Args.begin(), ie = Args.end(); + for (ArgList::const_iterator it = Args.begin(), ie = Args.end(); it != ie; ++it) { Arg *A = *it; @@ -669,19 +681,18 @@ void Driver::BuildActions(const ArgList &Args, ActionList &Actions) const { // 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. + // 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). + // Otherwise emit an error but still use a valid type to avoid + // spurious errors (e.g., no inputs). if (!Args.hasArg(options::OPT_E, false)) Diag(clang::diag::err_drv_unknown_stdin_type); Ty = types::TY_C; } else { - // Otherwise lookup by extension, and fallback to ObjectType - // if not found. We use a host hook here because Darwin at - // least has its own idea of what .s is. + // Otherwise lookup by extension, and fallback to ObjectType if not + // found. We use a host hook here because Darwin at least has its own + // idea of what .s is. if (const char *Ext = strrchr(Value, '.')) Ty = Host->lookupTypeForExtension(Ext + 1); @@ -692,7 +703,7 @@ void Driver::BuildActions(const ArgList &Args, ActionList &Actions) const { // -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)) @@ -706,28 +717,26 @@ void Driver::BuildActions(const ArgList &Args, ActionList &Actions) const { 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. + // 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(clang::diag::err_drv_no_such_file) << A->getValue(Args); 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. + // 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; + 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. + // 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(clang::diag::err_drv_unknown_language) << A->getValue(Args); InputType = types::TY_Object; @@ -740,9 +749,9 @@ void Driver::BuildActions(const ArgList &Args, ActionList &Actions) const { return; } - // Determine which compilation mode we are in. We look for options - // which affect the phase, starting with the earliest phases, and - // record which option we used to determine the final phase. + // Determine which compilation mode we are in. We look for options which + // affect the phase, starting with the earliest phases, and record which + // option we used to determine the final phase. Arg *FinalPhaseArg = 0; phases::ID FinalPhase; @@ -751,24 +760,25 @@ void Driver::BuildActions(const ArgList &Args, ActionList &Actions) const { (FinalPhaseArg = Args.getLastArg(options::OPT_M)) || (FinalPhaseArg = Args.getLastArg(options::OPT_MM))) { FinalPhase = phases::Preprocess; - - // -{fsyntax-only,-analyze,emit-llvm,S} only run up to the compiler. + + // -{fsyntax-only,-analyze,emit-ast,S} only run up to the compiler. } else if ((FinalPhaseArg = Args.getLastArg(options::OPT_fsyntax_only)) || (FinalPhaseArg = Args.getLastArg(options::OPT__analyze, options::OPT__analyze_auto)) || + (FinalPhaseArg = Args.getLastArg(options::OPT_emit_ast)) || (FinalPhaseArg = Args.getLastArg(options::OPT_S))) { FinalPhase = phases::Compile; // -c only runs up to the assembler. } else if ((FinalPhaseArg = Args.getLastArg(options::OPT_c))) { FinalPhase = phases::Assemble; - + // Otherwise do everything. } else FinalPhase = phases::Link; - // Reject -Z* at the top level, these options should never have been - // exposed by gcc. + // Reject -Z* at the top level, these options should never have been exposed + // by gcc. if (Arg *A = Args.getLastArg(options::OPT_Z_Joined)) Diag(clang::diag::err_drv_use_of_Z_option) << A->getAsString(Args); @@ -781,19 +791,28 @@ void Driver::BuildActions(const ArgList &Args, ActionList &Actions) const { unsigned NumSteps = types::getNumCompilationPhases(InputType); assert(NumSteps && "Invalid number of steps!"); - // If the first step comes after the final phase we are doing as - // part of this compilation, warn the user about it. + // If the first step comes after the final phase we are doing as part of + // this compilation, warn the user about it. phases::ID InitialPhase = types::getCompilationPhase(InputType, 0); if (InitialPhase > FinalPhase) { // Claim here to avoid the more general unused warning. InputArg->claim(); - Diag(clang::diag::warn_drv_input_file_unused) - << InputArg->getAsString(Args) - << getPhaseName(InitialPhase) - << FinalPhaseArg->getOption().getName(); + + // Special case '-E' warning on a previously preprocessed file to make + // more sense. + if (InitialPhase == phases::Compile && FinalPhase == phases::Preprocess && + getPreprocessedType(InputType) == types::TY_INVALID) + Diag(clang::diag::warn_drv_preprocessed_input_file_unused) + << InputArg->getAsString(Args) + << FinalPhaseArg->getOption().getName(); + else + Diag(clang::diag::warn_drv_input_file_unused) + << InputArg->getAsString(Args) + << getPhaseName(InitialPhase) + << FinalPhaseArg->getOption().getName(); continue; } - + // Build the pipeline for this file. Action *Current = new InputAction(*InputArg, InputType); for (unsigned i = 0; i != NumSteps; ++i) { @@ -811,9 +830,9 @@ void Driver::BuildActions(const ArgList &Args, ActionList &Actions) const { break; } - // Some types skip the assembler phase (e.g., llvm-bc), but we - // can't encode this in the steps because the intermediate type - // depends on arguments. Just special case here. + // Some types skip the assembler phase (e.g., llvm-bc), but we can't + // encode this in the steps because the intermediate type depends on + // arguments. Just special case here. if (Phase == phases::Assemble && Current->getType() != types::TY_PP_Asm) continue; @@ -852,16 +871,18 @@ Action *Driver::ConstructPhaseAction(const ArgList &Args, phases::ID Phase, return new PreprocessJobAction(Input, OutputTy); } case phases::Precompile: - return new PrecompileJobAction(Input, types::TY_PCH); + return new PrecompileJobAction(Input, types::TY_PCH); case phases::Compile: { if (Args.hasArg(options::OPT_fsyntax_only)) { return new CompileJobAction(Input, types::TY_Nothing); } else if (Args.hasArg(options::OPT__analyze, options::OPT__analyze_auto)) { return new AnalyzeJobAction(Input, types::TY_Plist); + } else if (Args.hasArg(options::OPT_emit_ast)) { + return new CompileJobAction(Input, types::TY_AST); } else if (Args.hasArg(options::OPT_emit_llvm) || Args.hasArg(options::OPT_flto) || Args.hasArg(options::OPT_O4)) { - types::ID Output = + types::ID Output = Args.hasArg(options::OPT_S) ? types::TY_LLVMAsm : types::TY_LLVMBC; return new CompileJobAction(Input, Output); } else { @@ -881,11 +902,10 @@ void Driver::BuildJobs(Compilation &C) const { bool SaveTemps = C.getArgs().hasArg(options::OPT_save_temps); bool UsePipes = C.getArgs().hasArg(options::OPT_pipe); - // FIXME: Pipes are forcibly disabled until we support executing - // them. + // FIXME: Pipes are forcibly disabled until we support executing them. if (!CCCPrintBindings) UsePipes = false; - + // -save-temps inhibits pipes. if (SaveTemps && UsePipes) { Diag(clang::diag::warn_drv_pipe_ignored_with_save_temps); @@ -894,32 +914,31 @@ void Driver::BuildJobs(Compilation &C) const { Arg *FinalOutput = C.getArgs().getLastArg(options::OPT_o); - // It is an error to provide a -o option if we are making multiple - // output files. + // 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 = C.getActions().begin(), + for (ActionList::const_iterator it = C.getActions().begin(), ie = C.getActions().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 = C.getActions().begin(), + for (ActionList::const_iterator it = C.getActions().begin(), ie = C.getActions().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. + // 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. + // FIXME: This is a hack; find a cleaner way to integrate this into the + // process. const char *LinkingOutput = 0; if (isa<LipoJobAction>(A)) { if (FinalOutput) @@ -929,41 +948,41 @@ void Driver::BuildJobs(Compilation &C) const { } InputInfo II; - BuildJobsForAction(C, A, &C.getDefaultToolChain(), + BuildJobsForAction(C, A, &C.getDefaultToolChain(), + /*BoundArch*/0, /*CanAcceptPipe*/ true, /*AtTopLevel*/ true, /*LinkingOutput*/ LinkingOutput, II); } - // If the user passed -Qunused-arguments or there were errors, don't - // warn about any unused arguments. - if (Diags.getNumErrors() || + // If the user passed -Qunused-arguments or there were errors, don't warn + // about any unused arguments. + if (Diags.getNumErrors() || C.getArgs().hasArg(options::OPT_Qunused_arguments)) return; // Claim -### here. (void) C.getArgs().hasArg(options::OPT__HASH_HASH_HASH); - + for (ArgList::const_iterator it = C.getArgs().begin(), ie = C.getArgs().end(); it != ie; ++it) { Arg *A = *it; - + // FIXME: It would be nice to be able to send the argument to the - // Diagnostic, so that extra values, position, and so on could be - // printed. + // Diagnostic, so that extra values, position, and so on could be printed. if (!A->isClaimed()) { if (A->getOption().hasNoArgumentUnused()) continue; - // Suppress the warning automatically if this is just a flag, - // and it is an instance of an argument we already claimed. + // Suppress the warning automatically if this is just a flag, and it is an + // instance of an argument we already claimed. const Option &Opt = A->getOption(); if (isa<FlagOption>(Opt)) { bool DuplicateClaimed = false; // FIXME: Use iterator. - for (ArgList::const_iterator it = C.getArgs().begin(), + for (ArgList::const_iterator it = C.getArgs().begin(), ie = C.getArgs().end(); it != ie; ++it) { if ((*it)->isClaimed() && (*it)->getOption().matches(Opt.getId())) { DuplicateClaimed = true; @@ -975,7 +994,7 @@ void Driver::BuildJobs(Compilation &C) const { continue; } - Diag(clang::diag::warn_drv_unused_argument) + Diag(clang::diag::warn_drv_unused_argument) << A->getAsString(C.getArgs()); } } @@ -984,21 +1003,21 @@ void Driver::BuildJobs(Compilation &C) const { void Driver::BuildJobsForAction(Compilation &C, const Action *A, const ToolChain *TC, + const char *BoundArch, bool CanAcceptPipe, bool AtTopLevel, const char *LinkingOutput, InputInfo &Result) const { - llvm::PrettyStackTraceString CrashInfo("Building compilation jobs for action"); + llvm::PrettyStackTraceString CrashInfo("Building compilation jobs"); bool UsePipes = C.getArgs().hasArg(options::OPT_pipe); - // FIXME: Pipes are forcibly disabled until we support executing - // them. + // FIXME: Pipes are forcibly disabled until we support executing them. if (!CCCPrintBindings) UsePipes = false; if (const InputAction *IA = dyn_cast<InputAction>(A)) { - // FIXME: It would be nice to not claim this here; maybe the old - // scheme of just using Args was better? + // FIXME: It would be nice to not claim this here; maybe the old scheme of + // just using Args was better? const Arg &Input = IA->getInputArg(); Input.claim(); if (isa<PositionalArg>(Input)) { @@ -1010,28 +1029,23 @@ void Driver::BuildJobsForAction(Compilation &C, } if (const BindArchAction *BAA = dyn_cast<BindArchAction>(A)) { - const char *ArchName = BAA->getArchName(); + const ToolChain *TC = &C.getDefaultToolChain(); + std::string Arch; - if (!ArchName) { - Arch = C.getDefaultToolChain().getArchName(); - ArchName = Arch.c_str(); - } - BuildJobsForAction(C, - *BAA->begin(), - Host->getToolChain(C.getArgs(), ArchName), - CanAcceptPipe, - AtTopLevel, - LinkingOutput, - Result); + if (BAA->getArchName()) + TC = Host->CreateToolChain(C.getArgs(), BAA->getArchName()); + + BuildJobsForAction(C, *BAA->begin(), TC, BAA->getArchName(), + 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). + + // 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())) { @@ -1050,18 +1064,16 @@ void Driver::BuildJobsForAction(Compilation &C, for (ActionList::const_iterator it = Inputs->begin(), ie = Inputs->end(); it != ie; ++it) { InputInfo II; - BuildJobsForAction(C, *it, TC, TryToUsePipeInput, - /*AtTopLevel*/false, - LinkingOutput, - II); + BuildJobsForAction(C, *it, TC, BoundArch, 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. + // 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) { @@ -1082,8 +1094,8 @@ void Driver::BuildJobsForAction(Compilation &C, // Always use the first input as the base input. const char *BaseInput = InputInfos[0].getBaseInput(); - // Determine the place to write output to (nothing, pipe, or - // filename) and where to put the new job. + // Determine the place to write output to (nothing, pipe, or filename) and + // where to put the new job. if (JA->getType() == types::TY_Nothing) { Result = InputInfo(A->getType(), BaseInput); } else if (OutputToPipe) { @@ -1091,8 +1103,8 @@ void Driver::BuildJobsForAction(Compilation &C, PipedJob *PJ = dyn_cast<PipedJob>(Dest); if (!PJ) { PJ = new PipedJob(); - // FIXME: Temporary hack so that -ccc-print-bindings work until - // we have pipe support. Please remove later. + // FIXME: Temporary hack so that -ccc-print-bindings work until we have + // pipe support. Please remove later. if (!CCCPrintBindings) cast<JobList>(Dest)->addJob(PJ); Dest = PJ; @@ -1113,12 +1125,12 @@ void Driver::BuildJobsForAction(Compilation &C, } llvm::errs() << "], output: " << Result.getAsString() << "\n"; } else { - T.ConstructJob(C, *JA, *Dest, Result, InputInfos, - C.getArgsForToolChain(TC), LinkingOutput); + T.ConstructJob(C, *JA, *Dest, Result, InputInfos, + C.getArgsForToolChain(TC, BoundArch), LinkingOutput); } } -const char *Driver::GetNamedOutputPath(Compilation &C, +const char *Driver::GetNamedOutputPath(Compilation &C, const JobAction &JA, const char *BaseInput, bool AtTopLevel) const { @@ -1131,7 +1143,7 @@ const char *Driver::GetNamedOutputPath(Compilation &C, // Output to a temporary file? if (!AtTopLevel && !C.getArgs().hasArg(options::OPT_save_temps)) { - std::string TmpName = + std::string TmpName = GetTemporaryPath(types::getTypeTempSuffix(JA.getType())); return C.addTempFile(C.getArgs().MakeArgString(TmpName.c_str())); } @@ -1156,8 +1168,7 @@ const char *Driver::GetNamedOutputPath(Compilation &C, NamedOutput = C.getArgs().MakeArgString(Suffixed.c_str()); } - // As an annoying special case, PCH generation doesn't strip the - // pathname. + // As an annoying special case, PCH generation doesn't strip the pathname. if (JA.getType() == types::TY_PCH) { BasePath.eraseComponent(); if (BasePath.isEmpty()) @@ -1170,43 +1181,41 @@ const char *Driver::GetNamedOutputPath(Compilation &C, } } -llvm::sys::Path Driver::GetFilePath(const char *Name, - const ToolChain &TC) const { +std::string Driver::GetFilePath(const char *Name, const ToolChain &TC) const { const ToolChain::path_list &List = TC.getFilePaths(); - for (ToolChain::path_list::const_iterator + for (ToolChain::path_list::const_iterator it = List.begin(), ie = List.end(); it != ie; ++it) { llvm::sys::Path P(*it); P.appendComponent(Name); if (P.exists()) - return P; + return P.str(); } - return llvm::sys::Path(Name); + return Name; } -llvm::sys::Path Driver::GetProgramPath(const char *Name, - const ToolChain &TC, - bool WantFile) const { +std::string Driver::GetProgramPath(const char *Name, const ToolChain &TC, + bool WantFile) const { const ToolChain::path_list &List = TC.getProgramPaths(); - for (ToolChain::path_list::const_iterator + for (ToolChain::path_list::const_iterator it = List.begin(), ie = List.end(); it != ie; ++it) { llvm::sys::Path P(*it); P.appendComponent(Name); if (WantFile ? P.exists() : P.canExecute()) - return P; + return P.str(); } // If all else failed, search the path. llvm::sys::Path P(llvm::sys::Program::FindProgramByName(Name)); if (!P.empty()) - return P; + return P.str(); - return llvm::sys::Path(Name); + return Name; } std::string Driver::GetTemporaryPath(const char *Suffix) const { - // FIXME: This is lame; sys::Path should provide this function (in - // particular, it should know how to find the temporary files dir). + // FIXME: This is lame; sys::Path should provide this function (in particular, + // it should know how to find the temporary files dir). std::string Error; const char *TmpDir = ::getenv("TMPDIR"); if (!TmpDir) @@ -1222,33 +1231,20 @@ std::string Driver::GetTemporaryPath(const char *Suffix) const { return ""; } - // FIXME: Grumble, makeUnique sometimes leaves the file around!? - // PR3837. + // FIXME: Grumble, makeUnique sometimes leaves the file around!? PR3837. P.eraseFromDisk(false, 0); P.appendSuffix(Suffix); - return P.toString(); + return P.str(); } const HostInfo *Driver::GetHostInfo(const char *TripleStr) const { llvm::PrettyStackTraceString CrashInfo("Constructing host"); llvm::Triple Triple(TripleStr); - // Normalize Arch a bit. - // - // FIXME: We shouldn't need to do this once everything goes through the triple - // interface. - if (Triple.getArchName() == "i686") - Triple.setArchName("i386"); - else if (Triple.getArchName() == "amd64") - Triple.setArchName("x86_64"); - else if (Triple.getArchName() == "ppc" || - Triple.getArchName() == "Power Macintosh") - Triple.setArchName("powerpc"); - else if (Triple.getArchName() == "ppc64") - Triple.setArchName("powerpc64"); - switch (Triple.getOS()) { + case llvm::Triple::AuroraUX: + return createAuroraUXHostInfo(*this, Triple); case llvm::Triple::Darwin: return createDarwinHostInfo(*this, Triple); case llvm::Triple::DragonFly: @@ -1265,17 +1261,10 @@ const HostInfo *Driver::GetHostInfo(const char *TripleStr) const { } bool Driver::ShouldUseClangCompiler(const Compilation &C, const JobAction &JA, - const std::string &ArchNameStr) const { - // FIXME: Remove this hack. - const char *ArchName = ArchNameStr.c_str(); - if (ArchNameStr == "powerpc") - ArchName = "ppc"; - else if (ArchNameStr == "powerpc64") - ArchName = "ppc64"; - - // Check if user requested no clang, or clang doesn't understand - // this type (we only handle single inputs for now). - if (!CCCUseClang || JA.size() != 1 || + const llvm::Triple &Triple) const { + // Check if user requested no clang, or clang doesn't understand this type (we + // only handle single inputs for now). + if (!CCCUseClang || JA.size() != 1 || !types::isAcceptedByClang((*JA.begin())->getType())) return false; @@ -1294,35 +1283,32 @@ bool Driver::ShouldUseClangCompiler(const Compilation &C, const JobAction &JA, return false; } - // Always use clang for precompiling, regardless of archs. PTH is - // platform independent, and this allows the use of the static - // analyzer on platforms we don't have full IRgen support for. - if (isa<PrecompileJobAction>(JA)) + // Always use clang for precompiling and AST generation, regardless of archs. + if (isa<PrecompileJobAction>(JA) || JA.getType() == types::TY_AST) return true; - // Finally, don't use clang if this isn't one of the user specified - // archs to build. - if (!CCCClangArchs.empty() && !CCCClangArchs.count(ArchName)) { - Diag(clang::diag::warn_drv_not_using_clang_arch) << ArchName; + // Finally, don't use clang if this isn't one of the user specified archs to + // build. + if (!CCCClangArchs.empty() && !CCCClangArchs.count(Triple.getArch())) { + Diag(clang::diag::warn_drv_not_using_clang_arch) << Triple.getArchName(); return false; } return true; } -/// GetReleaseVersion - Parse (([0-9]+)(.([0-9]+)(.([0-9]+)?))?)? and -/// return the grouped values as integers. Numbers which are not -/// provided are set to 0. +/// GetReleaseVersion - Parse (([0-9]+)(.([0-9]+)(.([0-9]+)?))?)? and return the +/// grouped values as integers. Numbers which are not provided are set to 0. /// -/// \return True if the entire string was parsed (9.2), or all groups -/// were parsed (10.3.5extrastuff). -bool Driver::GetReleaseVersion(const char *Str, unsigned &Major, +/// \return True if the entire string was parsed (9.2), or all groups were +/// parsed (10.3.5extrastuff). +bool Driver::GetReleaseVersion(const char *Str, unsigned &Major, unsigned &Minor, unsigned &Micro, bool &HadExtra) { HadExtra = false; Major = Minor = Micro = 0; - if (*Str == '\0') + if (*Str == '\0') return true; char *End; @@ -1331,7 +1317,7 @@ bool Driver::GetReleaseVersion(const char *Str, unsigned &Major, return true; if (*End != '.') return false; - + Str = End+1; Minor = (unsigned) strtol(Str, &End, 10); if (*Str != '\0' && *End == '\0') diff --git a/lib/Driver/HostInfo.cpp b/lib/Driver/HostInfo.cpp index 602a977..08c4ef4 100644 --- a/lib/Driver/HostInfo.cpp +++ b/lib/Driver/HostInfo.cpp @@ -22,13 +22,11 @@ #include "ToolChains.h" #include <cassert> - + using namespace clang::driver; HostInfo::HostInfo(const Driver &D, const llvm::Triple &_Triple) - : TheDriver(D), Triple(_Triple) -{ - + : TheDriver(D), Triple(_Triple) { } HostInfo::~HostInfo() { @@ -47,7 +45,7 @@ class DarwinHostInfo : public HostInfo { unsigned GCCVersion[3]; /// Cache of tool chains we have created. - mutable llvm::StringMap<ToolChain *> ToolChains; + mutable llvm::DenseMap<unsigned, ToolChain*> ToolChains; public: DarwinHostInfo(const Driver &D, const llvm::Triple &Triple); @@ -66,28 +64,22 @@ public: return Ty; } - virtual ToolChain *getToolChain(const ArgList &Args, - const char *ArchName) const; + virtual ToolChain *CreateToolChain(const ArgList &Args, + const char *ArchName) const; }; DarwinHostInfo::DarwinHostInfo(const Driver &D, const llvm::Triple& Triple) : HostInfo(D, Triple) { - - assert((getArchName() == "i386" || getArchName() == "x86_64" || - getArchName() == "powerpc" || getArchName() == "powerpc64" || - getArchName() == "arm") && - "Unknown Darwin arch."); + assert(Triple.getArch() != llvm::Triple::UnknownArch && "Invalid arch!"); assert(memcmp(&getOSName()[0], "darwin", 6) == 0 && "Unknown Darwin platform."); bool HadExtra; - if (!Driver::GetReleaseVersion(&getOSName()[6], - DarwinVersion[0], DarwinVersion[1], - DarwinVersion[2], HadExtra)) { - D.Diag(clang::diag::err_drv_invalid_darwin_version) - << getOSName(); - } - + if (!Driver::GetReleaseVersion(&getOSName()[6], + DarwinVersion[0], DarwinVersion[1], + DarwinVersion[2], HadExtra)) + D.Diag(clang::diag::err_drv_invalid_darwin_version) << getOSName(); + // We can only call 4.2.1 for now. GCCVersion[0] = 4; GCCVersion[1] = 2; @@ -95,73 +87,71 @@ DarwinHostInfo::DarwinHostInfo(const Driver &D, const llvm::Triple& Triple) } DarwinHostInfo::~DarwinHostInfo() { - for (llvm::StringMap<ToolChain*>::iterator + for (llvm::DenseMap<unsigned, ToolChain*>::iterator it = ToolChains.begin(), ie = ToolChains.end(); it != ie; ++it) delete it->second; } -bool DarwinHostInfo::useDriverDriver() const { +bool DarwinHostInfo::useDriverDriver() const { return true; } -ToolChain *DarwinHostInfo::getToolChain(const ArgList &Args, - const char *ArchName) const { - std::string Arch; +ToolChain *DarwinHostInfo::CreateToolChain(const ArgList &Args, + const char *ArchName) const { + llvm::Triple::ArchType Arch; + if (!ArchName) { // If we aren't looking for a specific arch, infer the default architecture // based on -arch and -m32/-m64 command line options. if (Arg *A = Args.getLastArg(options::OPT_arch)) { // The gcc driver behavior with multiple -arch flags wasn't consistent for // things which rely on a default architecture. We just use the last -arch - // to find the default tool chain. - Arch = A->getValue(Args); - - // Normalize arch name; we shouldn't be doing this here. - // - // FIXME: This should be unnecessary once everything moves over to using - // the ID based Triple interface. - if (Arch == "ppc") - Arch = "powerpc"; - else if (Arch == "ppc64") - Arch = "powerpc64"; + // to find the default tool chain (assuming it is valid.. + Arch = llvm::Triple::getArchTypeForDarwinArchName(A->getValue(Args)); + + // If it was invalid just use the host, we will reject this command line + // later. + if (Arch == llvm::Triple::UnknownArch) + Arch = getTriple().getArch(); } else { // Otherwise default to the arch of the host. - Arch = getArchName(); + Arch = getTriple().getArch(); } - ArchName = Arch.c_str(); - + // Honor -m32 and -m64 when finding the default tool chain. + // + // FIXME: Should this information be in llvm::Triple? if (Arg *A = Args.getLastArg(options::OPT_m32, options::OPT_m64)) { - if (Arch == "i386" || Arch == "x86_64") { - ArchName = (A->getOption().getId() == options::OPT_m32) ? "i386" : - "x86_64"; - } else if (Arch == "powerpc" || Arch == "powerpc64") { - ArchName = (A->getOption().getId() == options::OPT_m32) ? "powerpc" : - "powerpc64"; + if (A->getOption().getId() == options::OPT_m32) { + if (Arch == llvm::Triple::x86_64) + Arch = llvm::Triple::x86; + if (Arch == llvm::Triple::ppc64) + Arch = llvm::Triple::ppc; + } else { + if (Arch == llvm::Triple::x86) + Arch = llvm::Triple::x86_64; + if (Arch == llvm::Triple::ppc) + Arch = llvm::Triple::ppc64; } - } - } else { - // Normalize arch name; we shouldn't be doing this here. - // - // FIXME: This should be unnecessary once everything moves over to using the - // ID based Triple interface. - if (strcmp(ArchName, "ppc") == 0) - ArchName = "powerpc"; - else if (strcmp(ArchName, "ppc64") == 0) - ArchName = "powerpc64"; - } + } + } else + Arch = llvm::Triple::getArchTypeForDarwinArchName(ArchName); - ToolChain *&TC = ToolChains[ArchName]; + assert(Arch != llvm::Triple::UnknownArch && "Unexpected arch!"); + ToolChain *&TC = ToolChains[Arch]; if (!TC) { llvm::Triple TCTriple(getTriple()); - TCTriple.setArchName(ArchName); - - if (strcmp(ArchName, "i386") == 0 || strcmp(ArchName, "x86_64") == 0) - TC = new toolchains::Darwin_X86(*this, TCTriple, - DarwinVersion, - GCCVersion); + TCTriple.setArch(Arch); + + // If we recognized the arch, match it to the toolchains we support. + if (Arch == llvm::Triple::x86 || Arch == llvm::Triple::x86_64) { + // We still use the legacy DarwinGCC toolchain on X86. + TC = new toolchains::DarwinGCC(*this, TCTriple, DarwinVersion, GCCVersion, + false); + } else if (Arch == llvm::Triple::arm || Arch == llvm::Triple::thumb) + TC = new toolchains::DarwinClang(*this, TCTriple, DarwinVersion, true); else - TC = new toolchains::Darwin_GCC(*this, TCTriple); + TC = new toolchains::Darwin_Generic_GCC(*this, TCTriple); } return TC; @@ -185,11 +175,11 @@ public: return types::lookupTypeForExtension(Ext); } - virtual ToolChain *getToolChain(const ArgList &Args, - const char *ArchName) const; + virtual ToolChain *CreateToolChain(const ArgList &Args, + const char *ArchName) const; }; -UnknownHostInfo::UnknownHostInfo(const Driver &D, const llvm::Triple& Triple) +UnknownHostInfo::UnknownHostInfo(const Driver &D, const llvm::Triple& Triple) : HostInfo(D, Triple) { } @@ -199,15 +189,15 @@ UnknownHostInfo::~UnknownHostInfo() { delete it->second; } -bool UnknownHostInfo::useDriverDriver() const { +bool UnknownHostInfo::useDriverDriver() const { return false; } -ToolChain *UnknownHostInfo::getToolChain(const ArgList &Args, - const char *ArchName) const { - assert(!ArchName && +ToolChain *UnknownHostInfo::CreateToolChain(const ArgList &Args, + const char *ArchName) const { + assert(!ArchName && "Unexpected arch name on platform without driver driver support."); - + // Automatically handle some instances of -m32/-m64 we know about. std::string Arch = getArchName(); ArchName = Arch.c_str(); @@ -221,8 +211,8 @@ ToolChain *UnknownHostInfo::getToolChain(const ArgList &Args, ArchName = (A->getOption().getId() == options::OPT_m32) ? "powerpc" : "powerpc64"; } - } - + } + ToolChain *&TC = ToolChains[ArchName]; if (!TC) { llvm::Triple TCTriple(getTriple()); @@ -242,7 +232,7 @@ class OpenBSDHostInfo : public HostInfo { mutable llvm::StringMap<ToolChain*> ToolChains; public: - OpenBSDHostInfo(const Driver &D, const llvm::Triple& Triple) + OpenBSDHostInfo(const Driver &D, const llvm::Triple& Triple) : HostInfo(D, Triple) {} ~OpenBSDHostInfo(); @@ -252,8 +242,8 @@ public: return types::lookupTypeForExtension(Ext); } - virtual ToolChain *getToolChain(const ArgList &Args, - const char *ArchName) const; + virtual ToolChain *CreateToolChain(const ArgList &Args, + const char *ArchName) const; }; OpenBSDHostInfo::~OpenBSDHostInfo() { @@ -262,18 +252,18 @@ OpenBSDHostInfo::~OpenBSDHostInfo() { delete it->second; } -bool OpenBSDHostInfo::useDriverDriver() const { +bool OpenBSDHostInfo::useDriverDriver() const { return false; } -ToolChain *OpenBSDHostInfo::getToolChain(const ArgList &Args, - const char *ArchName) const { - assert(!ArchName && +ToolChain *OpenBSDHostInfo::CreateToolChain(const ArgList &Args, + const char *ArchName) const { + assert(!ArchName && "Unexpected arch name on platform without driver driver support."); - + std::string Arch = getArchName(); ArchName = Arch.c_str(); - + ToolChain *&TC = ToolChains[ArchName]; if (!TC) { llvm::Triple TCTriple(getTriple()); @@ -285,6 +275,55 @@ ToolChain *OpenBSDHostInfo::getToolChain(const ArgList &Args, return TC; } +// AuroraUX Host Info + +/// AuroraUXHostInfo - AuroraUX host information implementation. +class AuroraUXHostInfo : public HostInfo { + /// Cache of tool chains we have created. + mutable llvm::StringMap<ToolChain*> ToolChains; + +public: + AuroraUXHostInfo(const Driver &D, const llvm::Triple& Triple) + : HostInfo(D, Triple) {} + ~AuroraUXHostInfo(); + + virtual bool useDriverDriver() const; + + virtual types::ID lookupTypeForExtension(const char *Ext) const { + return types::lookupTypeForExtension(Ext); + } + + virtual ToolChain *CreateToolChain(const ArgList &Args, + const char *ArchName) const; +}; + +AuroraUXHostInfo::~AuroraUXHostInfo() { + for (llvm::StringMap<ToolChain*>::iterator + it = ToolChains.begin(), ie = ToolChains.end(); it != ie; ++it) + delete it->second; +} + +bool AuroraUXHostInfo::useDriverDriver() const { + return false; +} + +ToolChain *AuroraUXHostInfo::CreateToolChain(const ArgList &Args, + const char *ArchName) const { + assert(!ArchName && + "Unexpected arch name on platform without driver driver support."); + + ToolChain *&TC = ToolChains[getArchName()]; + + if (!TC) { + llvm::Triple TCTriple(getTriple()); + TCTriple.setArchName(getArchName()); + + TC = new toolchains::AuroraUX(*this, TCTriple); + } + + return TC; +} + // FreeBSD Host Info /// FreeBSDHostInfo - FreeBSD host information implementation. @@ -293,7 +332,7 @@ class FreeBSDHostInfo : public HostInfo { mutable llvm::StringMap<ToolChain*> ToolChains; public: - FreeBSDHostInfo(const Driver &D, const llvm::Triple& Triple) + FreeBSDHostInfo(const Driver &D, const llvm::Triple& Triple) : HostInfo(D, Triple) {} ~FreeBSDHostInfo(); @@ -303,8 +342,8 @@ public: return types::lookupTypeForExtension(Ext); } - virtual ToolChain *getToolChain(const ArgList &Args, - const char *ArchName) const; + virtual ToolChain *CreateToolChain(const ArgList &Args, + const char *ArchName) const; }; FreeBSDHostInfo::~FreeBSDHostInfo() { @@ -313,17 +352,17 @@ FreeBSDHostInfo::~FreeBSDHostInfo() { delete it->second; } -bool FreeBSDHostInfo::useDriverDriver() const { +bool FreeBSDHostInfo::useDriverDriver() const { return false; } -ToolChain *FreeBSDHostInfo::getToolChain(const ArgList &Args, - const char *ArchName) const { +ToolChain *FreeBSDHostInfo::CreateToolChain(const ArgList &Args, + const char *ArchName) const { bool Lib32 = false; - assert(!ArchName && + assert(!ArchName && "Unexpected arch name on platform without driver driver support."); - + // On x86_64 we need to be able to compile 32-bits binaries as well. // Compiling 64-bit binaries on i386 is not supported. We don't have a // lib64. @@ -332,8 +371,8 @@ ToolChain *FreeBSDHostInfo::getToolChain(const ArgList &Args, if (Args.hasArg(options::OPT_m32) && getArchName() == "x86_64") { ArchName = "i386"; Lib32 = true; - } - + } + ToolChain *&TC = ToolChains[ArchName]; if (!TC) { llvm::Triple TCTriple(getTriple()); @@ -363,8 +402,8 @@ public: return types::lookupTypeForExtension(Ext); } - virtual ToolChain *getToolChain(const ArgList &Args, - const char *ArchName) const; + virtual ToolChain *CreateToolChain(const ArgList &Args, + const char *ArchName) const; }; DragonFlyHostInfo::~DragonFlyHostInfo() { @@ -373,13 +412,13 @@ DragonFlyHostInfo::~DragonFlyHostInfo() { delete it->second; } -bool DragonFlyHostInfo::useDriverDriver() const { +bool DragonFlyHostInfo::useDriverDriver() const { return false; } -ToolChain *DragonFlyHostInfo::getToolChain(const ArgList &Args, - const char *ArchName) const { - assert(!ArchName && +ToolChain *DragonFlyHostInfo::CreateToolChain(const ArgList &Args, + const char *ArchName) const { + assert(!ArchName && "Unexpected arch name on platform without driver driver support."); ToolChain *&TC = ToolChains[getArchName()]; @@ -412,8 +451,8 @@ public: return types::lookupTypeForExtension(Ext); } - virtual ToolChain *getToolChain(const ArgList &Args, - const char *ArchName) const; + virtual ToolChain *CreateToolChain(const ArgList &Args, + const char *ArchName) const; }; LinuxHostInfo::~LinuxHostInfo() { @@ -422,14 +461,14 @@ LinuxHostInfo::~LinuxHostInfo() { delete it->second; } -bool LinuxHostInfo::useDriverDriver() const { +bool LinuxHostInfo::useDriverDriver() const { return false; } -ToolChain *LinuxHostInfo::getToolChain(const ArgList &Args, - const char *ArchName) const { +ToolChain *LinuxHostInfo::CreateToolChain(const ArgList &Args, + const char *ArchName) const { - assert(!ArchName && + assert(!ArchName && "Unexpected arch name on platform without driver driver support."); // Automatically handle some instances of -m32/-m64 we know about. @@ -462,19 +501,25 @@ ToolChain *LinuxHostInfo::getToolChain(const ArgList &Args, } const HostInfo * +clang::driver::createAuroraUXHostInfo(const Driver &D, + const llvm::Triple& Triple){ + return new AuroraUXHostInfo(D, Triple); +} + +const HostInfo * clang::driver::createDarwinHostInfo(const Driver &D, const llvm::Triple& Triple){ return new DarwinHostInfo(D, Triple); } const HostInfo * -clang::driver::createOpenBSDHostInfo(const Driver &D, +clang::driver::createOpenBSDHostInfo(const Driver &D, const llvm::Triple& Triple) { return new OpenBSDHostInfo(D, Triple); } const HostInfo * -clang::driver::createFreeBSDHostInfo(const Driver &D, +clang::driver::createFreeBSDHostInfo(const Driver &D, const llvm::Triple& Triple) { return new FreeBSDHostInfo(D, Triple); } diff --git a/lib/Driver/Job.cpp b/lib/Driver/Job.cpp index 1b0ea18..280e7c4 100644 --- a/lib/Driver/Job.cpp +++ b/lib/Driver/Job.cpp @@ -14,9 +14,9 @@ using namespace clang::driver; Job::~Job() {} -Command::Command(const Action &_Source, const char *_Executable, +Command::Command(const Action &_Source, const char *_Executable, const ArgStringList &_Arguments) - : Job(CommandClass), Source(_Source), Executable(_Executable), + : Job(CommandClass), Source(_Source), Executable(_Executable), Arguments(_Arguments) { } @@ -30,4 +30,4 @@ void Job::addCommand(Command *C) { else cast<JobList>(this)->addJob(C); } - + diff --git a/lib/Driver/Makefile b/lib/Driver/Makefile index d163f0f..4c3ca5c 100644 --- a/lib/Driver/Makefile +++ b/lib/Driver/Makefile @@ -12,17 +12,9 @@ LIBRARYNAME := clangDriver BUILD_ARCHIVE = 1 CXXFLAGS = -fno-rtti +CPPFLAGS += -I$(PROJ_SRC_DIR)/../../include -I$(PROJ_OBJ_DIR)/../../include +ifdef CLANG_VENDOR +CPPFLAGS += -DCLANG_VENDOR='"$(CLANG_VENDOR) "' +endif include $(LEVEL)/Makefile.common - -SVN_REVISION := $(shell cd $(PROJ_SRC_DIR)/../.. && svnversion) - -CPP.Defines += -I$(PROJ_SRC_DIR)/../../include -I$(PROJ_OBJ_DIR)/../../include \ - -DSVN_REVISION='"$(SVN_REVISION)"' - -$(ObjDir)/.ver-svn .ver: $(ObjDir)/.dir - @if [ '$(SVN_REVISION)' != '$(shell cat $(ObjDir)/.ver-svn 2>/dev/null)' ]; then\ - echo '$(SVN_REVISION)' > $(ObjDir)/.ver-svn; \ - fi -$(ObjDir)/.ver-svn: .ver -$(ObjDir)/Driver.o: $(ObjDir)/.ver-svn diff --git a/lib/Driver/OptTable.cpp b/lib/Driver/OptTable.cpp index 7ea6a8b..affd1c5 100644 --- a/lib/Driver/OptTable.cpp +++ b/lib/Driver/OptTable.cpp @@ -77,7 +77,7 @@ static Info OptionInfos[] = { { "<input>", "d", 0, 0, Option::InputClass, OPT_INVALID, OPT_INVALID, 0 }, // The UnknownOption info { "<unknown>", "", 0, 0, Option::UnknownClass, OPT_INVALID, OPT_INVALID, 0 }, - + #define OPTION(NAME, ID, KIND, GROUP, ALIAS, FLAGS, PARAM, \ HELPTEXT, METAVAR) \ { NAME, FLAGS, HELPTEXT, METAVAR, \ @@ -91,7 +91,11 @@ static Info &getInfo(unsigned id) { return OptionInfos[id - 1]; } -OptTable::OptTable() : Options(new Option*[numOptions]()) { +OptTable::OptTable() : Options(new Option*[numOptions]) { + // Explicitly zero initialize the error to work around a bug in array + // value-initialization on MinGW with gcc 4.3.5. + memset(Options, 0, sizeof(*Options) * numOptions); + // Find start of normal options. FirstSearchableOption = 0; for (unsigned i = OPT_UNKNOWN + 1; i < LastOption; ++i) { @@ -120,10 +124,10 @@ OptTable::OptTable() : Options(new Option*[numOptions]()) { assert(0 && "Options are not in order!"); } } -#endif +#endif } -OptTable::~OptTable() { +OptTable::~OptTable() { for (unsigned i = 0; i < numOptions; ++i) delete Options[i]; delete[] Options; @@ -164,7 +168,7 @@ const Option *OptTable::getOption(options::ID id) const { Option *OptTable::constructOption(options::ID id) const { Info &info = getInfo(id); - const OptionGroup *Group = + const OptionGroup *Group = cast_or_null<OptionGroup>(getOption((options::ID) info.GroupID)); const Option *Alias = getOption((options::ID) info.AliasID); @@ -195,10 +199,10 @@ Option *OptTable::constructOption(options::ID id) const { for (const char *s = info.Flags; *s; ++s) { switch (*s) { default: assert(0 && "Invalid option flag."); - case 'J': + case 'J': assert(info.Kind == Option::SeparateClass && "Invalid option."); Opt->setForceJoinedRender(true); break; - case 'S': + case 'S': assert(info.Kind == Option::JoinedClass && "Invalid option."); Opt->setForceSeparateRender(true); break; case 'd': Opt->setDriverOption(true); break; diff --git a/lib/Driver/Option.cpp b/lib/Driver/Option.cpp index cad2bbf..c2ace05 100644 --- a/lib/Driver/Option.cpp +++ b/lib/Driver/Option.cpp @@ -17,18 +17,17 @@ using namespace clang::driver; Option::Option(OptionClass _Kind, options::ID _ID, const char *_Name, - const OptionGroup *_Group, const Option *_Alias) + const OptionGroup *_Group, const Option *_Alias) : Kind(_Kind), ID(_ID), Name(_Name), Group(_Group), Alias(_Alias), Unsupported(false), LinkerInput(false), NoOptAsInput(false), ForceSeparateRender(false), ForceJoinedRender(false), - DriverOption(false), NoArgumentUnused(false) -{ + DriverOption(false), NoArgumentUnused(false) { // Multi-level aliases are not supported, and alias options cannot // have groups. This just simplifies option tracking, it is not an // inherent limitation. assert((!Alias || (!Alias->Alias && !Group)) && - "Multi-level aliases and aliases with groups are unsupported."); + "Multi-level aliases and aliases with groups are unsupported."); } Option::~Option() { @@ -59,12 +58,12 @@ void Option::dump() const { llvm::errs() << " Group:"; Group->dump(); } - + if (Alias) { llvm::errs() << " Alias:"; Alias->dump(); } - + if (const MultiArgOption *MOA = dyn_cast<MultiArgOption>(this)) llvm::errs() << " NumArgs:" << MOA->getNumArgs(); @@ -77,10 +76,10 @@ bool Option::matches(const Option *Opt) const { return matches(Opt->getAlias()); if (Alias) return Alias->matches(Opt); - + if (this == Opt) return true; - + if (Group) return Group->matches(Opt); return false; @@ -93,16 +92,16 @@ bool Option::matches(options::ID Id) const { // the option table). if (Alias) return Alias->matches(Id); - + if (ID == Id) return true; - + if (Group) return Group->matches(Id); return false; } -OptionGroup::OptionGroup(options::ID ID, const char *Name, +OptionGroup::OptionGroup(options::ID ID, const char *Name, const OptionGroup *Group) : Option(Option::GroupClass, ID, Name, Group, 0) { } @@ -130,13 +129,13 @@ Arg *UnknownOption::accept(const InputArgList &Args, unsigned &Index) const { return 0; } -FlagOption::FlagOption(options::ID ID, const char *Name, +FlagOption::FlagOption(options::ID ID, const char *Name, const OptionGroup *Group, const Option *Alias) : Option(Option::FlagClass, ID, Name, Group, Alias) { } Arg *FlagOption::accept(const InputArgList &Args, unsigned &Index) const { - // Matches iff this is an exact match. + // Matches iff this is an exact match. // FIXME: Avoid strlen. if (strlen(getName()) != strlen(Args.getArgString(Index))) return 0; @@ -144,7 +143,7 @@ Arg *FlagOption::accept(const InputArgList &Args, unsigned &Index) const { return new FlagArg(this, Index++); } -JoinedOption::JoinedOption(options::ID ID, const char *Name, +JoinedOption::JoinedOption(options::ID ID, const char *Name, const OptionGroup *Group, const Option *Alias) : Option(Option::JoinedClass, ID, Name, Group, Alias) { } @@ -154,30 +153,30 @@ Arg *JoinedOption::accept(const InputArgList &Args, unsigned &Index) const { return new JoinedArg(this, Index++); } -CommaJoinedOption::CommaJoinedOption(options::ID ID, const char *Name, - const OptionGroup *Group, +CommaJoinedOption::CommaJoinedOption(options::ID ID, const char *Name, + const OptionGroup *Group, const Option *Alias) : Option(Option::CommaJoinedClass, ID, Name, Group, Alias) { } -Arg *CommaJoinedOption::accept(const InputArgList &Args, +Arg *CommaJoinedOption::accept(const InputArgList &Args, unsigned &Index) const { // Always matches. We count the commas now so we can answer // getNumValues easily. - + // Get the suffix string. // FIXME: Avoid strlen, and move to helper method? const char *Suffix = Args.getArgString(Index) + strlen(getName()); return new CommaJoinedArg(this, Index++, Suffix); } -SeparateOption::SeparateOption(options::ID ID, const char *Name, +SeparateOption::SeparateOption(options::ID ID, const char *Name, const OptionGroup *Group, const Option *Alias) : Option(Option::SeparateClass, ID, Name, Group, Alias) { } Arg *SeparateOption::accept(const InputArgList &Args, unsigned &Index) const { - // Matches iff this is an exact match. + // Matches iff this is an exact match. // FIXME: Avoid strlen. if (strlen(getName()) != strlen(Args.getArgString(Index))) return 0; @@ -189,15 +188,15 @@ Arg *SeparateOption::accept(const InputArgList &Args, unsigned &Index) const { return new SeparateArg(this, Index - 2, 1); } -MultiArgOption::MultiArgOption(options::ID ID, const char *Name, - const OptionGroup *Group, const Option *Alias, +MultiArgOption::MultiArgOption(options::ID ID, const char *Name, + const OptionGroup *Group, const Option *Alias, unsigned _NumArgs) : Option(Option::MultiArgClass, ID, Name, Group, Alias), NumArgs(_NumArgs) { assert(NumArgs > 1 && "Invalid MultiArgOption!"); } Arg *MultiArgOption::accept(const InputArgList &Args, unsigned &Index) const { - // Matches iff this is an exact match. + // Matches iff this is an exact match. // FIXME: Avoid strlen. if (strlen(getName()) != strlen(Args.getArgString(Index))) return 0; @@ -210,12 +209,12 @@ Arg *MultiArgOption::accept(const InputArgList &Args, unsigned &Index) const { } JoinedOrSeparateOption::JoinedOrSeparateOption(options::ID ID, const char *Name, - const OptionGroup *Group, + const OptionGroup *Group, const Option *Alias) : Option(Option::JoinedOrSeparateClass, ID, Name, Group, Alias) { } -Arg *JoinedOrSeparateOption::accept(const InputArgList &Args, +Arg *JoinedOrSeparateOption::accept(const InputArgList &Args, unsigned &Index) const { // If this is not an exact match, it is a joined arg. // FIXME: Avoid strlen. @@ -227,17 +226,17 @@ Arg *JoinedOrSeparateOption::accept(const InputArgList &Args, if (Index > Args.getNumInputArgStrings()) return 0; - return new SeparateArg(this, Index - 2, 1); + return new SeparateArg(this, Index - 2, 1); } JoinedAndSeparateOption::JoinedAndSeparateOption(options::ID ID, - const char *Name, - const OptionGroup *Group, + const char *Name, + const OptionGroup *Group, const Option *Alias) : Option(Option::JoinedAndSeparateClass, ID, Name, Group, Alias) { } -Arg *JoinedAndSeparateOption::accept(const InputArgList &Args, +Arg *JoinedAndSeparateOption::accept(const InputArgList &Args, unsigned &Index) const { // Always matches. diff --git a/lib/Driver/Tool.cpp b/lib/Driver/Tool.cpp index 6f6589a..781e0a7 100644 --- a/lib/Driver/Tool.cpp +++ b/lib/Driver/Tool.cpp @@ -11,7 +11,7 @@ using namespace clang::driver; -Tool::Tool(const char *_Name, const ToolChain &TC) : Name(_Name), +Tool::Tool(const char *_Name, const ToolChain &TC) : Name(_Name), TheToolChain(TC) { } diff --git a/lib/Driver/ToolChain.cpp b/lib/Driver/ToolChain.cpp index 20ed31b..abe9c81 100644 --- a/lib/Driver/ToolChain.cpp +++ b/lib/Driver/ToolChain.cpp @@ -22,14 +22,14 @@ ToolChain::ToolChain(const HostInfo &_Host, const llvm::Triple &_Triple) ToolChain::~ToolChain() { } -llvm::sys::Path ToolChain::GetFilePath(const Compilation &C, - const char *Name) const { +std::string ToolChain::GetFilePath(const Compilation &C, + const char *Name) const { return Host.getDriver().GetFilePath(Name, *this); - + } -llvm::sys::Path ToolChain::GetProgramPath(const Compilation &C, - const char *Name, - bool WantFile) const { +std::string ToolChain::GetProgramPath(const Compilation &C, + const char *Name, + bool WantFile) const { return Host.getDriver().GetProgramPath(Name, *this, WantFile); } diff --git a/lib/Driver/ToolChains.cpp b/lib/Driver/ToolChains.cpp index f663ed4..a5a48ad 100644 --- a/lib/Driver/ToolChains.cpp +++ b/lib/Driver/ToolChains.cpp @@ -17,6 +17,7 @@ #include "clang/Driver/Option.h" #include "llvm/ADT/StringExtras.h" +#include "llvm/Support/ErrorHandling.h" #include "llvm/Support/raw_ostream.h" #include "llvm/System/Path.h" @@ -25,21 +26,34 @@ using namespace clang::driver; using namespace clang::driver::toolchains; -/// Darwin_X86 - Darwin tool chain for i386 and x86_64. +/// Darwin - Darwin tool chain for i386 and x86_64. -Darwin_X86::Darwin_X86(const HostInfo &Host, const llvm::Triple& Triple, - const unsigned (&_DarwinVersion)[3], - const unsigned (&_GCCVersion)[3]) - : ToolChain(Host, Triple) { +Darwin::Darwin(const HostInfo &Host, const llvm::Triple& Triple, + const unsigned (&_DarwinVersion)[3], bool _IsIPhoneOS) + : ToolChain(Host, Triple), + IsIPhoneOS(_IsIPhoneOS) +{ DarwinVersion[0] = _DarwinVersion[0]; DarwinVersion[1] = _DarwinVersion[1]; DarwinVersion[2] = _DarwinVersion[2]; + + llvm::raw_string_ostream(MacosxVersionMin) + << "10." << DarwinVersion[0] - 4 << '.' << DarwinVersion[1]; + + // FIXME: Lift default up. + IPhoneOSVersionMin = "3.0"; +} + +DarwinGCC::DarwinGCC(const HostInfo &Host, const llvm::Triple& Triple, + const unsigned (&DarwinVersion)[3], + const unsigned (&_GCCVersion)[3], bool IsIPhoneOS) + : Darwin(Host, Triple, DarwinVersion, IsIPhoneOS) +{ GCCVersion[0] = _GCCVersion[0]; GCCVersion[1] = _GCCVersion[1]; GCCVersion[2] = _GCCVersion[2]; - llvm::raw_string_ostream(MacosxVersionMin) - << "10." << DarwinVersion[0] - 4 << '.' << DarwinVersion[1]; + // Set up the tool chain paths to match gcc. ToolChainDir = "i686-apple-darwin"; ToolChainDir += llvm::utostr(DarwinVersion[0]); @@ -54,32 +68,32 @@ Darwin_X86::Darwin_X86(const HostInfo &Host, const llvm::Triple& Triple, if (getArchName() == "x86_64") { Path = getHost().getDriver().Dir; Path += "/../lib/gcc/"; - Path += getToolChainDir(); + Path += ToolChainDir; Path += "/x86_64"; getFilePaths().push_back(Path); Path = "/usr/lib/gcc/"; - Path += getToolChainDir(); + Path += ToolChainDir; Path += "/x86_64"; getFilePaths().push_back(Path); } - + Path = getHost().getDriver().Dir; Path += "/../lib/gcc/"; - Path += getToolChainDir(); + Path += ToolChainDir; getFilePaths().push_back(Path); Path = "/usr/lib/gcc/"; - Path += getToolChainDir(); + Path += ToolChainDir; getFilePaths().push_back(Path); Path = getHost().getDriver().Dir; Path += "/../libexec/gcc/"; - Path += getToolChainDir(); + Path += ToolChainDir; getProgramPaths().push_back(Path); Path = "/usr/libexec/gcc/"; - Path += getToolChainDir(); + Path += ToolChainDir; getProgramPaths().push_back(Path); Path = getHost().getDriver().Dir; @@ -89,17 +103,16 @@ Darwin_X86::Darwin_X86(const HostInfo &Host, const llvm::Triple& Triple, getProgramPaths().push_back(getHost().getDriver().Dir); } -Darwin_X86::~Darwin_X86() { +Darwin::~Darwin() { // Free tool implementations. for (llvm::DenseMap<unsigned, Tool*>::iterator it = Tools.begin(), ie = Tools.end(); it != ie; ++it) delete it->second; } -Tool &Darwin_X86::SelectTool(const Compilation &C, - const JobAction &JA) const { +Tool &Darwin::SelectTool(const Compilation &C, const JobAction &JA) const { Action::ActionClass Key; - if (getHost().getDriver().ShouldUseClangCompiler(C, JA, getArchName())) + if (getHost().getDriver().ShouldUseClangCompiler(C, JA, getTriple())) Key = Action::AnalyzeJobClass; else Key = JA.getKind(); @@ -120,7 +133,7 @@ Tool &Darwin_X86::SelectTool(const Compilation &C, case Action::AssembleJobClass: T = new tools::darwin::Assemble(*this); break; case Action::LinkJobClass: - T = new tools::darwin::Link(*this, MacosxVersionMin.c_str()); break; + T = new tools::darwin::Link(*this); break; case Action::LipoJobClass: T = new tools::darwin::Lipo(*this); break; } @@ -129,7 +142,136 @@ Tool &Darwin_X86::SelectTool(const Compilation &C, return *T; } -DerivedArgList *Darwin_X86::TranslateArgs(InputArgList &Args) const { +void DarwinGCC::AddLinkSearchPathArgs(const ArgList &Args, + ArgStringList &CmdArgs) const { + // FIXME: Derive these correctly. + if (getArchName() == "x86_64") { + CmdArgs.push_back(Args.MakeArgString("-L/usr/lib/gcc/" + ToolChainDir + + "/x86_64")); + // Intentionally duplicated for (temporary) gcc bug compatibility. + CmdArgs.push_back(Args.MakeArgString("-L/usr/lib/gcc/" + ToolChainDir + + "/x86_64")); + } + CmdArgs.push_back(Args.MakeArgString("-L/usr/lib/" + ToolChainDir)); + CmdArgs.push_back(Args.MakeArgString("-L/usr/lib/gcc/" + ToolChainDir)); + // Intentionally duplicated for (temporary) gcc bug compatibility. + CmdArgs.push_back(Args.MakeArgString("-L/usr/lib/gcc/" + ToolChainDir)); + CmdArgs.push_back(Args.MakeArgString("-L/usr/lib/gcc/" + ToolChainDir + + "/../../../" + ToolChainDir)); + CmdArgs.push_back(Args.MakeArgString("-L/usr/lib/gcc/" + ToolChainDir + + "/../../..")); +} + +void DarwinGCC::AddLinkRuntimeLibArgs(const ArgList &Args, + ArgStringList &CmdArgs) const { + unsigned MacosxVersionMin[3]; + getMacosxVersionMin(Args, MacosxVersionMin); + + // Derived from libgcc and lib specs but refactored. + if (Args.hasArg(options::OPT_static)) { + CmdArgs.push_back("-lgcc_static"); + } else { + if (Args.hasArg(options::OPT_static_libgcc)) { + CmdArgs.push_back("-lgcc_eh"); + } else if (Args.hasArg(options::OPT_miphoneos_version_min_EQ)) { + // Derived from darwin_iphoneos_libgcc spec. + if (isIPhoneOS()) { + CmdArgs.push_back("-lgcc_s.1"); + } else { + CmdArgs.push_back("-lgcc_s.10.5"); + } + } else if (Args.hasArg(options::OPT_shared_libgcc) || + // FIXME: -fexceptions -fno-exceptions means no exceptions + Args.hasArg(options::OPT_fexceptions) || + Args.hasArg(options::OPT_fgnu_runtime)) { + // FIXME: This is probably broken on 10.3? + if (isMacosxVersionLT(MacosxVersionMin, 10, 5)) + CmdArgs.push_back("-lgcc_s.10.4"); + else if (isMacosxVersionLT(MacosxVersionMin, 10, 6)) + CmdArgs.push_back("-lgcc_s.10.5"); + } else { + if (isMacosxVersionLT(MacosxVersionMin, 10, 3, 9)) + ; // Do nothing. + else if (isMacosxVersionLT(MacosxVersionMin, 10, 5)) + CmdArgs.push_back("-lgcc_s.10.4"); + else if (isMacosxVersionLT(MacosxVersionMin, 10, 6)) + CmdArgs.push_back("-lgcc_s.10.5"); + } + + if (isIPhoneOS() || isMacosxVersionLT(MacosxVersionMin, 10, 6)) { + CmdArgs.push_back("-lgcc"); + CmdArgs.push_back("-lSystem"); + } else { + CmdArgs.push_back("-lSystem"); + CmdArgs.push_back("-lgcc"); + } + } +} + +DarwinClang::DarwinClang(const HostInfo &Host, const llvm::Triple& Triple, + const unsigned (&DarwinVersion)[3], + bool IsIPhoneOS) + : Darwin(Host, Triple, DarwinVersion, IsIPhoneOS) +{ + // Add the relative libexec dir (for clang-cc). + // + // FIXME: We should sink clang-cc into libexec/clang/<version>/. + std::string Path = getHost().getDriver().Dir; + Path += "/../libexec"; + getProgramPaths().push_back(Path); + + // We expect 'as', 'ld', etc. to be adjacent to our install dir. + getProgramPaths().push_back(getHost().getDriver().Dir); +} + +void DarwinClang::AddLinkSearchPathArgs(const ArgList &Args, + ArgStringList &CmdArgs) const { + // The Clang toolchain uses explicit paths for internal libraries. +} + +void DarwinClang::AddLinkRuntimeLibArgs(const ArgList &Args, + ArgStringList &CmdArgs) const { + // Check for static linking. + if (Args.hasArg(options::OPT_static)) { + // FIXME: We need to have compiler-rt available (perhaps as + // libclang_static.a) to link against. + return; + } + + // Reject -static-libgcc for now, we can deal with this when and if someone + // cares. This is useful in situations where someone wants to statically link + // something like libstdc++, and needs its runtime support routines. + if (const Arg *A = Args.getLastArg(options::OPT_static_libgcc)) { + getHost().getDriver().Diag(clang::diag::err_drv_unsupported_opt) + << A->getAsString(Args); + return; + } + + // Otherwise link libSystem, which should have the support routines. + // + // FIXME: This is only true for 10.6 and beyond. Legacy support isn't + // critical, but it should work... we should just link in the static + // compiler-rt library. + CmdArgs.push_back("-lSystem"); +} + +void Darwin::getMacosxVersionMin(const ArgList &Args, + unsigned (&Res)[3]) const { + if (Arg *A = Args.getLastArg(options::OPT_mmacosx_version_min_EQ)) { + bool HadExtra; + if (!Driver::GetReleaseVersion(A->getValue(Args), Res[0], Res[1], Res[2], + HadExtra) || + HadExtra) { + const Driver &D = getHost().getDriver(); + D.Diag(clang::diag::err_drv_invalid_version_number) + << A->getAsString(Args); + } + } else + return getMacosxVersion(Res); +} + +DerivedArgList *Darwin::TranslateArgs(InputArgList &Args, + const char *BoundArch) const { DerivedArgList *DAL = new DerivedArgList(Args, false); const OptTable &Opts = getHost().getDriver().getOpts(); @@ -138,30 +280,36 @@ DerivedArgList *Darwin_X86::TranslateArgs(InputArgList &Args) const { // more opaque. For now, we follow gcc closely solely for the // purpose of easily achieving feature parity & testability. Once we // have something that works, we should reevaluate each translation - // and try to push it down into tool specific logic. + // and try to push it down into tool specific logic. - Arg *OSXVersion = + Arg *OSXVersion = Args.getLastArg(options::OPT_mmacosx_version_min_EQ, false); Arg *iPhoneVersion = - Args.getLastArg(options::OPT_miphoneos_version_min_EQ, false); + Args.getLastArg(options::OPT_miphoneos_version_min_EQ, false); if (OSXVersion && iPhoneVersion) { getHost().getDriver().Diag(clang::diag::err_drv_argument_not_allowed_with) << OSXVersion->getAsString(Args) - << iPhoneVersion->getAsString(Args); + << iPhoneVersion->getAsString(Args); } else if (!OSXVersion && !iPhoneVersion) { // Chose the default version based on the arch. // - // FIXME: This will need to be fixed when we merge in arm support. - - // Look for MACOSX_DEPLOYMENT_TARGET, otherwise use the version - // from the host. - const char *Version = ::getenv("MACOSX_DEPLOYMENT_TARGET"); - if (!Version) - Version = MacosxVersionMin.c_str(); - const Option *O = Opts.getOption(options::OPT_mmacosx_version_min_EQ); - DAL->append(DAL->MakeJoinedArg(0, O, Version)); + // FIXME: Are there iPhone overrides for this? + + if (!isIPhoneOS()) { + // Look for MACOSX_DEPLOYMENT_TARGET, otherwise use the version + // from the host. + const char *Version = ::getenv("MACOSX_DEPLOYMENT_TARGET"); + if (!Version) + Version = MacosxVersionMin.c_str(); + const Option *O = Opts.getOption(options::OPT_mmacosx_version_min_EQ); + DAL->append(DAL->MakeJoinedArg(0, O, Version)); + } else { + const char *Version = IPhoneOSVersionMin.c_str(); + const Option *O = Opts.getOption(options::OPT_miphoneos_version_min_EQ); + DAL->append(DAL->MakeJoinedArg(0, O, Version)); + } } - + for (ArgList::iterator it = Args.begin(), ie = Args.end(); it != ie; ++it) { Arg *A = *it; @@ -174,7 +322,7 @@ DerivedArgList *Darwin_X86::TranslateArgs(InputArgList &Args) const { // interface for this. unsigned Prev, Index = Prev = A->getIndex() + 1; Arg *XarchArg = Opts.ParseOneArg(Args, Index); - + // If the argument parsing failed or more than one argument was // consumed, the -Xarch_ argument's parameter tried to consume // extra arguments. Emit an error and ignore. @@ -183,7 +331,7 @@ DerivedArgList *Darwin_X86::TranslateArgs(InputArgList &Args) const { // driver behavior; that isn't going to work in our model. We // use isDriverOption() as an approximation, although things // like -O4 are going to slip through. - if (!XarchArg || Index > Prev + 1 || + if (!XarchArg || Index > Prev + 1 || XarchArg->getOption().isDriverOption()) { getHost().getDriver().Diag(clang::diag::err_drv_invalid_Xarch_argument) << A->getAsString(Args); @@ -192,7 +340,7 @@ DerivedArgList *Darwin_X86::TranslateArgs(InputArgList &Args) const { XarchArg->setBaseArg(A); A = XarchArg; - } + } // Sob. These is strictly gcc compatible for the time being. Apple // gcc translates options twice, which means that self-expanding @@ -209,7 +357,7 @@ DerivedArgList *Darwin_X86::TranslateArgs(InputArgList &Args) const { DAL->append(DAL->MakeFlagArg(A, Opts.getOption(options::OPT_static))); DAL->append(DAL->MakeFlagArg(A, Opts.getOption(options::OPT_static))); break; - + case options::OPT_dependency_file: DAL->append(DAL->MakeSeparateArg(A, Opts.getOption(options::OPT_MF), A->getValue(Args))); @@ -270,35 +418,98 @@ DerivedArgList *Darwin_X86::TranslateArgs(InputArgList &Args) const { } } - // FIXME: Actually, gcc always adds this, but it is filtered for - // duplicates somewhere. This also changes the order of things, so - // look it up. - if (getArchName() == "x86_64") - if (!Args.hasArg(options::OPT_m64, false)) + if (getTriple().getArch() == llvm::Triple::x86 || + getTriple().getArch() == llvm::Triple::x86_64) + if (!Args.hasArg(options::OPT_mtune_EQ, false)) + DAL->append(DAL->MakeJoinedArg(0, Opts.getOption(options::OPT_mtune_EQ), + "core2")); + + // Add the arch options based on the particular spelling of -arch, to match + // how the driver driver works. + if (BoundArch) { + llvm::StringRef Name = BoundArch; + const Option *MCpu = Opts.getOption(options::OPT_mcpu_EQ); + const Option *MArch = Opts.getOption(options::OPT_march_EQ); + + // This code must be kept in sync with LLVM's getArchTypeForDarwinArch, + // which defines the list of which architectures we accept. + if (Name == "ppc") + ; + else if (Name == "ppc601") + DAL->append(DAL->MakeJoinedArg(0, MCpu, "601")); + else if (Name == "ppc603") + DAL->append(DAL->MakeJoinedArg(0, MCpu, "603")); + else if (Name == "ppc604") + DAL->append(DAL->MakeJoinedArg(0, MCpu, "604")); + else if (Name == "ppc604e") + DAL->append(DAL->MakeJoinedArg(0, MCpu, "604e")); + else if (Name == "ppc750") + DAL->append(DAL->MakeJoinedArg(0, MCpu, "750")); + else if (Name == "ppc7400") + DAL->append(DAL->MakeJoinedArg(0, MCpu, "7400")); + else if (Name == "ppc7450") + DAL->append(DAL->MakeJoinedArg(0, MCpu, "7450")); + else if (Name == "ppc970") + DAL->append(DAL->MakeJoinedArg(0, MCpu, "970")); + + else if (Name == "ppc64") + DAL->append(DAL->MakeFlagArg(0, Opts.getOption(options::OPT_m64))); + + else if (Name == "i386") + ; + else if (Name == "i486") + DAL->append(DAL->MakeJoinedArg(0, MArch, "i486")); + else if (Name == "i586") + DAL->append(DAL->MakeJoinedArg(0, MArch, "i586")); + else if (Name == "i686") + DAL->append(DAL->MakeJoinedArg(0, MArch, "i686")); + else if (Name == "pentium") + DAL->append(DAL->MakeJoinedArg(0, MArch, "pentium")); + else if (Name == "pentium2") + DAL->append(DAL->MakeJoinedArg(0, MArch, "pentium2")); + else if (Name == "pentpro") + DAL->append(DAL->MakeJoinedArg(0, MArch, "pentiumpro")); + else if (Name == "pentIIm3") + DAL->append(DAL->MakeJoinedArg(0, MArch, "pentium2")); + + else if (Name == "x86_64") DAL->append(DAL->MakeFlagArg(0, Opts.getOption(options::OPT_m64))); - if (!Args.hasArg(options::OPT_mtune_EQ, false)) - DAL->append(DAL->MakeJoinedArg(0, Opts.getOption(options::OPT_mtune_EQ), - "core2")); + else if (Name == "arm") + DAL->append(DAL->MakeJoinedArg(0, MArch, "armv4t")); + else if (Name == "armv4t") + DAL->append(DAL->MakeJoinedArg(0, MArch, "armv4t")); + else if (Name == "armv5") + DAL->append(DAL->MakeJoinedArg(0, MArch, "armv5tej")); + else if (Name == "xscale") + DAL->append(DAL->MakeJoinedArg(0, MArch, "xscale")); + else if (Name == "armv6") + DAL->append(DAL->MakeJoinedArg(0, MArch, "armv6k")); + else if (Name == "armv7") + DAL->append(DAL->MakeJoinedArg(0, MArch, "armv7a")); + + else + llvm::llvm_unreachable("invalid Darwin arch"); + } return DAL; -} +} -bool Darwin_X86::IsMathErrnoDefault() const { - return false; +bool Darwin::IsMathErrnoDefault() const { + return false; } -bool Darwin_X86::IsUnwindTablesDefault() const { +bool Darwin::IsUnwindTablesDefault() const { // FIXME: Gross; we should probably have some separate target // definition, possibly even reusing the one in clang. return getArchName() == "x86_64"; } -const char *Darwin_X86::GetDefaultRelocationModel() const { +const char *Darwin::GetDefaultRelocationModel() const { return "pic"; } -const char *Darwin_X86::GetForcedPicModel() const { +const char *Darwin::GetForcedPicModel() const { if (getArchName() == "x86_64") return "pic"; return 0; @@ -309,13 +520,12 @@ const char *Darwin_X86::GetForcedPicModel() const { /// command line options. Generic_GCC::Generic_GCC(const HostInfo &Host, const llvm::Triple& Triple) - : ToolChain(Host, Triple) -{ + : ToolChain(Host, Triple) { std::string Path(getHost().getDriver().Dir); Path += "/../libexec"; getProgramPaths().push_back(Path); - getProgramPaths().push_back(getHost().getDriver().Dir); + getProgramPaths().push_back(getHost().getDriver().Dir); } Generic_GCC::~Generic_GCC() { @@ -325,10 +535,10 @@ Generic_GCC::~Generic_GCC() { delete it->second; } -Tool &Generic_GCC::SelectTool(const Compilation &C, +Tool &Generic_GCC::SelectTool(const Compilation &C, const JobAction &JA) const { Action::ActionClass Key; - if (getHost().getDriver().ShouldUseClangCompiler(C, JA, getArchName())) + if (getHost().getDriver().ShouldUseClangCompiler(C, JA, getTriple())) Key = Action::AnalyzeJobClass; else Key = JA.getKind(); @@ -351,7 +561,7 @@ Tool &Generic_GCC::SelectTool(const Compilation &C, T = new tools::gcc::Assemble(*this); break; case Action::LinkJobClass: T = new tools::gcc::Link(*this); break; - + // This is a bit ungeneric, but the only platform using a driver // driver is Darwin. case Action::LipoJobClass: @@ -362,8 +572,8 @@ Tool &Generic_GCC::SelectTool(const Compilation &C, return *T; } -bool Generic_GCC::IsMathErrnoDefault() const { - return true; +bool Generic_GCC::IsMathErrnoDefault() const { + return true; } bool Generic_GCC::IsUnwindTablesDefault() const { @@ -380,7 +590,8 @@ const char *Generic_GCC::GetForcedPicModel() const { return 0; } -DerivedArgList *Generic_GCC::TranslateArgs(InputArgList &Args) const { +DerivedArgList *Generic_GCC::TranslateArgs(InputArgList &Args, + const char *BoundArch) const { return new DerivedArgList(Args, true); } @@ -394,7 +605,7 @@ OpenBSD::OpenBSD(const HostInfo &Host, const llvm::Triple& Triple) Tool &OpenBSD::SelectTool(const Compilation &C, const JobAction &JA) const { Action::ActionClass Key; - if (getHost().getDriver().ShouldUseClangCompiler(C, JA, getArchName())) + if (getHost().getDriver().ShouldUseClangCompiler(C, JA, getTriple())) Key = Action::AnalyzeJobClass; else Key = JA.getKind(); @@ -429,7 +640,7 @@ FreeBSD::FreeBSD(const HostInfo &Host, const llvm::Triple& Triple, bool Lib32) Tool &FreeBSD::SelectTool(const Compilation &C, const JobAction &JA) const { Action::ActionClass Key; - if (getHost().getDriver().ShouldUseClangCompiler(C, JA, getArchName())) + if (getHost().getDriver().ShouldUseClangCompiler(C, JA, getTriple())) Key = Action::AnalyzeJobClass; else Key = JA.getKind(); @@ -449,6 +660,48 @@ Tool &FreeBSD::SelectTool(const Compilation &C, const JobAction &JA) const { return *T; } +/// AuroraUX - AuroraUX tool chain which can call as(1) and ld(1) directly. + +AuroraUX::AuroraUX(const HostInfo &Host, const llvm::Triple& Triple) + : Generic_GCC(Host, Triple) { + + // Path mangling to find libexec + std::string Path(getHost().getDriver().Dir); + + Path += "/../libexec"; + getProgramPaths().push_back(Path); + getProgramPaths().push_back(getHost().getDriver().Dir); + + getFilePaths().push_back(getHost().getDriver().Dir + "/../lib"); + getFilePaths().push_back("/usr/lib"); + getFilePaths().push_back("/usr/sfw/lib"); + getFilePaths().push_back("/opt/gcc4/lib"); + +} + +Tool &AuroraUX::SelectTool(const Compilation &C, const JobAction &JA) const { + Action::ActionClass Key; + if (getHost().getDriver().ShouldUseClangCompiler(C, JA, getTriple())) + Key = Action::AnalyzeJobClass; + else + Key = JA.getKind(); + + Tool *&T = Tools[Key]; + if (!T) { + switch (Key) { + case Action::AssembleJobClass: + T = new tools::auroraux::Assemble(*this); break; + case Action::LinkJobClass: + T = new tools::auroraux::Link(*this); break; + default: + T = &Generic_GCC::SelectTool(C, JA); + } + } + + return *T; +} + + /// Linux toolchain (very bare-bones at the moment). Linux::Linux(const HostInfo &Host, const llvm::Triple& Triple) @@ -456,6 +709,15 @@ Linux::Linux(const HostInfo &Host, const llvm::Triple& Triple) getFilePaths().push_back(getHost().getDriver().Dir + "/../lib/clang/1.0/"); getFilePaths().push_back("/lib/"); getFilePaths().push_back("/usr/lib/"); + + // Depending on the Linux distribution, any combination of lib{,32,64} is + // possible. E.g. Debian uses lib and lib32 for mixed i386/x86-64 systems, + // openSUSE uses lib and lib64 for the same purpose. + getFilePaths().push_back("/lib32/"); + getFilePaths().push_back("/usr/lib32/"); + getFilePaths().push_back("/lib64/"); + getFilePaths().push_back("/usr/lib64/"); + // FIXME: Figure out some way to get gcc's libdir // (e.g. /usr/lib/gcc/i486-linux-gnu/4.3/ for Ubuntu 32-bit); we need // crtbegin.o/crtend.o/etc., and want static versions of various @@ -475,7 +737,7 @@ DragonFly::DragonFly(const HostInfo &Host, const llvm::Triple& Triple) Path += "/../libexec"; getProgramPaths().push_back(Path); - getProgramPaths().push_back(getHost().getDriver().Dir); + getProgramPaths().push_back(getHost().getDriver().Dir); getFilePaths().push_back(getHost().getDriver().Dir + "/../lib"); getFilePaths().push_back("/usr/lib"); @@ -484,7 +746,7 @@ DragonFly::DragonFly(const HostInfo &Host, const llvm::Triple& Triple) Tool &DragonFly::SelectTool(const Compilation &C, const JobAction &JA) const { Action::ActionClass Key; - if (getHost().getDriver().ShouldUseClangCompiler(C, JA, getArchName())) + if (getHost().getDriver().ShouldUseClangCompiler(C, JA, getTriple())) Key = Action::AnalyzeJobClass; else Key = JA.getKind(); diff --git a/lib/Driver/ToolChains.h b/lib/Driver/ToolChains.h index c921d52..6088d96 100644 --- a/lib/Driver/ToolChains.h +++ b/lib/Driver/ToolChains.h @@ -22,9 +22,9 @@ namespace clang { namespace driver { namespace toolchains { - /// Generic_GCC - A tool chain using the 'gcc' command to perform - /// all subcommands; this relies on gcc translating the majority of - /// command line options. +/// Generic_GCC - A tool chain using the 'gcc' command to perform +/// all subcommands; this relies on gcc translating the majority of +/// command line options. class VISIBILITY_HIDDEN Generic_GCC : public ToolChain { protected: mutable llvm::DenseMap<unsigned, Tool*> Tools; @@ -33,7 +33,8 @@ public: Generic_GCC(const HostInfo &Host, const llvm::Triple& Triple); ~Generic_GCC(); - virtual DerivedArgList *TranslateArgs(InputArgList &Args) const; + virtual DerivedArgList *TranslateArgs(InputArgList &Args, + const char *BoundArch) const; virtual Tool &SelectTool(const Compilation &C, const JobAction &JA) const; @@ -43,30 +44,35 @@ public: virtual const char *GetForcedPicModel() const; }; - /// Darwin_X86 - Darwin tool chain for i386 an x86_64. -class VISIBILITY_HIDDEN Darwin_X86 : public ToolChain { +/// Darwin - The base Darwin tool chain. +class VISIBILITY_HIDDEN Darwin : public ToolChain { mutable llvm::DenseMap<unsigned, Tool*> Tools; /// Darwin version of tool chain. unsigned DarwinVersion[3]; - /// GCC version to use. - unsigned GCCVersion[3]; - - /// The directory suffix for this tool chain. - std::string ToolChainDir; + /// Whether this is this an iPhoneOS toolchain. + // + // FIXME: This should go away, such differences should be completely + // determined by the target triple. + bool IsIPhoneOS; /// The default macosx-version-min of this tool chain; empty until /// initialized. mutable std::string MacosxVersionMin; + /// The default iphoneos-version-min of this tool chain. + std::string IPhoneOSVersionMin; + const char *getMacosxVersionMin() const; public: - Darwin_X86(const HostInfo &Host, const llvm::Triple& Triple, - const unsigned (&DarwinVersion)[3], - const unsigned (&GCCVersion)[3]); - ~Darwin_X86(); + Darwin(const HostInfo &Host, const llvm::Triple& Triple, + const unsigned (&DarwinVersion)[3], bool IsIPhoneOS); + ~Darwin(); + + /// @name Darwin Specific Toolchain API + /// { void getDarwinVersion(unsigned (&Res)[3]) const { Res[0] = DarwinVersion[0]; @@ -80,15 +86,53 @@ public: Res[2] = DarwinVersion[1]; } + /// getMacosxVersionMin - Get the effective -mmacosx-version-min, which is + /// either the -mmacosx-version-min, or the current version if unspecified. + void getMacosxVersionMin(const ArgList &Args, unsigned (&Res)[3]) const; + + static bool isMacosxVersionLT(unsigned (&A)[3], unsigned (&B)[3]) { + for (unsigned i=0; i < 3; ++i) { + if (A[i] > B[i]) return false; + if (A[i] < B[i]) return true; + } + return false; + } + + static bool isMacosxVersionLT(unsigned (&A)[3], + unsigned V0, unsigned V1=0, unsigned V2=0) { + unsigned B[3] = { V0, V1, V2 }; + return isMacosxVersionLT(A, B); + } + const char *getMacosxVersionStr() const { return MacosxVersionMin.c_str(); } - const std::string &getToolChainDir() const { - return ToolChainDir; + const char *getIPhoneOSVersionStr() const { + return IPhoneOSVersionMin.c_str(); } - virtual DerivedArgList *TranslateArgs(InputArgList &Args) const; + /// AddLinkSearchPathArgs - Add the linker search paths to \arg CmdArgs. + /// + /// \param Args - The input argument list. + /// \param CmdArgs [out] - The command argument list to append the paths + /// (prefixed by -L) to. + virtual void AddLinkSearchPathArgs(const ArgList &Args, + ArgStringList &CmdArgs) const = 0; + + /// AddLinkRuntimeLibArgs - Add the linker arguments to link the compiler + /// runtime library. + virtual void AddLinkRuntimeLibArgs(const ArgList &Args, + ArgStringList &CmdArgs) const = 0; + + bool isIPhoneOS() const { return IsIPhoneOS; } + + /// } + /// @name ToolChain Implementation + /// { + + virtual DerivedArgList *TranslateArgs(InputArgList &Args, + const char *BoundArch) const; virtual Tool &SelectTool(const Compilation &C, const JobAction &JA) const; @@ -96,17 +140,69 @@ public: virtual bool IsUnwindTablesDefault() const; virtual const char *GetDefaultRelocationModel() const; virtual const char *GetForcedPicModel() const; + + /// } +}; + +/// DarwinClang - The Darwin toolchain used by Clang. +class VISIBILITY_HIDDEN DarwinClang : public Darwin { +public: + DarwinClang(const HostInfo &Host, const llvm::Triple& Triple, + const unsigned (&DarwinVersion)[3], bool IsIPhoneOS); + + /// @name Darwin ToolChain Implementation + /// { + + virtual void AddLinkSearchPathArgs(const ArgList &Args, + ArgStringList &CmdArgs) const; + + virtual void AddLinkRuntimeLibArgs(const ArgList &Args, + ArgStringList &CmdArgs) const; + + /// } }; - /// Darwin_GCC - Generic Darwin tool chain using gcc. -class VISIBILITY_HIDDEN Darwin_GCC : public Generic_GCC { +/// DarwinGCC - The Darwin toolchain used by GCC. +class VISIBILITY_HIDDEN DarwinGCC : public Darwin { + /// GCC version to use. + unsigned GCCVersion[3]; + + /// The directory suffix for this tool chain. + std::string ToolChainDir; + public: - Darwin_GCC(const HostInfo &Host, const llvm::Triple& Triple) + DarwinGCC(const HostInfo &Host, const llvm::Triple& Triple, + const unsigned (&DarwinVersion)[3], const unsigned (&GCCVersion)[3], + bool IsIPhoneOS); + + /// @name Darwin ToolChain Implementation + /// { + + virtual void AddLinkSearchPathArgs(const ArgList &Args, + ArgStringList &CmdArgs) const; + + virtual void AddLinkRuntimeLibArgs(const ArgList &Args, + ArgStringList &CmdArgs) const; + + /// } +}; + +/// Darwin_Generic_GCC - Generic Darwin tool chain using gcc. +class VISIBILITY_HIDDEN Darwin_Generic_GCC : public Generic_GCC { +public: + Darwin_Generic_GCC(const HostInfo &Host, const llvm::Triple& Triple) : Generic_GCC(Host, Triple) {} virtual const char *GetDefaultRelocationModel() const { return "pic"; } }; +class VISIBILITY_HIDDEN AuroraUX : public Generic_GCC { +public: + AuroraUX(const HostInfo &Host, const llvm::Triple& Triple); + + virtual Tool &SelectTool(const Compilation &C, const JobAction &JA) const; +}; + class VISIBILITY_HIDDEN OpenBSD : public Generic_GCC { public: OpenBSD(const HostInfo &Host, const llvm::Triple& Triple); diff --git a/lib/Driver/Tools.cpp b/lib/Driver/Tools.cpp index d198a54..fc91e4c 100644 --- a/lib/Driver/Tools.cpp +++ b/lib/Driver/Tools.cpp @@ -21,7 +21,8 @@ #include "clang/Driver/ToolChain.h" #include "clang/Driver/Util.h" -#include "llvm/ADT/SmallVector.h" +#include "llvm/ADT/SmallString.h" +#include "llvm/ADT/Twine.h" #include "llvm/Support/Format.h" #include "llvm/Support/raw_ostream.h" @@ -33,25 +34,42 @@ using namespace clang::driver::tools; static const char *MakeFormattedString(const ArgList &Args, const llvm::format_object_base &Fmt) { - std::string Str; - llvm::raw_string_ostream(Str) << Fmt; - return Args.MakeArgString(Str.c_str()); + llvm::SmallString<256> Str; + llvm::raw_svector_ostream(Str) << Fmt; + return Args.MakeArgString(Str.str()); } -void Clang::AddPreprocessingOptions(const Driver &D, +/// CheckPreprocessingOptions - Perform some validation of preprocessing +/// arguments that is shared with gcc. +static void CheckPreprocessingOptions(const Driver &D, const ArgList &Args) { + if (Arg *A = Args.getLastArg(options::OPT_C, options::OPT_CC)) + if (!Args.hasArg(options::OPT_E)) + D.Diag(clang::diag::err_drv_argument_only_allowed_with) + << A->getAsString(Args) << "-E"; +} + +/// CheckCodeGenerationOptions - Perform some validation of code generation +/// arguments that is shared with gcc. +static void CheckCodeGenerationOptions(const Driver &D, const ArgList &Args) { + // In gcc, only ARM checks this, but it seems reasonable to check universally. + if (Args.hasArg(options::OPT_static)) + if (const Arg *A = Args.getLastArg(options::OPT_dynamic, + options::OPT_mdynamic_no_pic)) + D.Diag(clang::diag::err_drv_argument_not_allowed_with) + << A->getAsString(Args) << "-static"; +} + +void Clang::AddPreprocessingOptions(const Driver &D, const ArgList &Args, ArgStringList &CmdArgs, const InputInfo &Output, const InputInfoList &Inputs) const { Arg *A; - if ((A = Args.getLastArg(options::OPT_C)) || - (A = Args.getLastArg(options::OPT_CC))) { - if (!Args.hasArg(options::OPT_E)) - D.Diag(clang::diag::err_drv_argument_only_allowed_with) - << A->getAsString(Args) << "-E"; - A->render(Args, CmdArgs); - } + CheckPreprocessingOptions(D, Args); + + Args.AddLastArg(CmdArgs, options::OPT_C); + Args.AddLastArg(CmdArgs, options::OPT_CC); // Handle dependency file generation. if ((A = Args.getLastArg(options::OPT_M)) || @@ -77,6 +95,7 @@ void Clang::AddPreprocessingOptions(const Driver &D, CmdArgs.push_back(DepFile); // Add an -MT option if the user didn't specify their own. + // // FIXME: This should use -MQ, when we support it. if (!Args.hasArg(options::OPT_MT) && !Args.hasArg(options::OPT_MQ)) { const char *DepTarget; @@ -94,7 +113,7 @@ void Clang::AddPreprocessingOptions(const Driver &D, P.eraseSuffix(); P.appendSuffix("o"); - DepTarget = Args.MakeArgString(P.getLast().c_str()); + DepTarget = Args.MakeArgString(P.getLast()); } CmdArgs.push_back("-MT"); @@ -109,13 +128,13 @@ void Clang::AddPreprocessingOptions(const Driver &D, Args.AddLastArg(CmdArgs, options::OPT_MP); Args.AddAllArgs(CmdArgs, options::OPT_MT); - // FIXME: Use iterator. - // Add -i* options, and automatically translate to // -include-pch/-include-pth for transparent PCH support. It's // wonky, but we include looking for .gch so we can support seamless // replacement into a build system already set up to be generating // .gch files. + // + // FIXME: Use iterator. for (ArgList::const_iterator it = Args.begin(), ie = Args.end(); it != ie; ++it) { const Arg *A = *it; @@ -130,25 +149,25 @@ void Clang::AddPreprocessingOptions(const Driver &D, P.appendSuffix("pch"); if (P.exists()) FoundPCH = true; - else + else P.eraseSuffix(); } if (!FoundPCH) { P.appendSuffix("pth"); - if (P.exists()) + if (P.exists()) FoundPTH = true; else P.eraseSuffix(); - } - + } + if (!FoundPCH && !FoundPTH) { P.appendSuffix("gch"); if (P.exists()) { FoundPCH = D.CCCUsePCH; FoundPTH = !D.CCCUsePCH; } - else + else P.eraseSuffix(); } @@ -158,7 +177,7 @@ void Clang::AddPreprocessingOptions(const Driver &D, CmdArgs.push_back("-include-pch"); else CmdArgs.push_back("-include-pth"); - CmdArgs.push_back(Args.MakeArgString(P.c_str())); + CmdArgs.push_back(Args.MakeArgString(P.str())); continue; } } @@ -181,6 +200,308 @@ void Clang::AddPreprocessingOptions(const Driver &D, options::OPT_Xpreprocessor); } +/// getARMTargetCPU - Get the (LLVM) name of the ARM cpu we are targetting. +// +// FIXME: tblgen this. +static llvm::StringRef getARMTargetCPU(const ArgList &Args) { + // FIXME: Warn on inconsistent use of -mcpu and -march. + + // If we have -mcpu=, use that. + if (Arg *A = Args.getLastArg(options::OPT_mcpu_EQ)) + return A->getValue(Args); + + // Otherwise, if we have -march= choose the base CPU for that arch. + if (Arg *A = Args.getLastArg(options::OPT_march_EQ)) { + llvm::StringRef MArch = A->getValue(Args); + + if (MArch == "armv2" || MArch == "armv2a") + return "arm2"; + if (MArch == "armv3") + return "arm6"; + if (MArch == "armv3m") + return "arm7m"; + if (MArch == "armv4" || MArch == "armv4t") + return "arm7tdmi"; + if (MArch == "armv5" || MArch == "armv5t") + return "arm10tdmi"; + if (MArch == "armv5e" || MArch == "armv5te") + return "arm1026ejs"; + if (MArch == "armv5tej") + return "arm926ejs"; + if (MArch == "armv6" || MArch == "armv6k") + return "arm1136jf-s"; + if (MArch == "armv6j") + return "arm1136j-s"; + if (MArch == "armv6z" || MArch == "armv6zk") + return "arm1176jzf-s"; + if (MArch == "armv6t2") + return "arm1156t2-s"; + if (MArch == "armv7" || MArch == "armv7a" || MArch == "armv7-a") + return "cortex-a8"; + if (MArch == "armv7r" || MArch == "armv7-r") + return "cortex-r4"; + if (MArch == "armv7m" || MArch == "armv7-m") + return "cortex-m3"; + if (MArch == "ep9312") + return "ep9312"; + if (MArch == "iwmmxt") + return "iwmmxt"; + if (MArch == "xscale") + return "xscale"; + } + + // Otherwise return the most base CPU LLVM supports. + return "arm7tdmi"; +} + +/// getLLVMArchSuffixForARM - Get the LLVM arch name to use for a particular +/// CPU. +// +// FIXME: This is redundant with -mcpu, why does LLVM use this. +// FIXME: tblgen this, or kill it! +static const char *getLLVMArchSuffixForARM(llvm::StringRef CPU) { + if (CPU == "arm7tdmi" || CPU == "arm7tdmi-s" || CPU == "arm710t" || + CPU == "arm720t" || CPU == "arm9" || CPU == "arm9tdmi" || + CPU == "arm920" || CPU == "arm920t" || CPU == "arm922t" || + CPU == "arm940t" || CPU == "ep9312") + return "v4t"; + + if (CPU == "arm10tdmi" || CPU == "arm1020t") + return "v5"; + + if (CPU == "arm9e" || CPU == "arm926ej-s" || CPU == "arm946e-s" || + CPU == "arm966e-s" || CPU == "arm968e-s" || CPU == "arm10e" || + CPU == "arm1020e" || CPU == "arm1022e" || CPU == "xscale" || + CPU == "iwmmxt") + return "v5e"; + + if (CPU == "arm1136j-s" || CPU == "arm1136jf-s" || CPU == "arm1176jz-s" || + CPU == "arm1176jzf-s" || CPU == "mpcorenovfp" || CPU == "mpcore") + return "v6"; + + if (CPU == "arm1156t2-s" || CPU == "arm1156t2f-s") + return "v6t2"; + + if (CPU == "cortex-a8" || CPU == "cortex-a9") + return "v7"; + + return ""; +} + +/// getLLVMTriple - Get the LLVM triple to use for a particular toolchain, which +/// may depend on command line arguments. +static std::string getLLVMTriple(const ToolChain &TC, const ArgList &Args) { + switch (TC.getTriple().getArch()) { + default: + return TC.getTripleString(); + + case llvm::Triple::arm: + case llvm::Triple::thumb: { + // FIXME: Factor into subclasses. + llvm::Triple Triple = TC.getTriple(); + + // Thumb2 is the default for V7 on Darwin. + // + // FIXME: Thumb should just be another -target-feaure, not in the triple. + llvm::StringRef Suffix = getLLVMArchSuffixForARM(getARMTargetCPU(Args)); + bool ThumbDefault = + (Suffix == "v7" && TC.getTriple().getOS() == llvm::Triple::Darwin); + std::string ArchName = "arm"; + if (Args.hasFlag(options::OPT_mthumb, options::OPT_mno_thumb, ThumbDefault)) + ArchName = "thumb"; + Triple.setArchName(ArchName + Suffix.str()); + + return Triple.getTriple(); + } + } +} + +void Clang::AddARMTargetArgs(const ArgList &Args, + ArgStringList &CmdArgs) const { + const Driver &D = getToolChain().getHost().getDriver(); + + // Select the ABI to use. + // + // FIXME: Support -meabi. + const char *ABIName = 0; + if (Arg *A = Args.getLastArg(options::OPT_mabi_EQ)) { + ABIName = A->getValue(Args); + } else { + // Select the default based on the platform. + switch (getToolChain().getTriple().getOS()) { + // FIXME: Is this right for non-Darwin and non-Linux? + default: + ABIName = "aapcs"; + break; + + case llvm::Triple::Darwin: + ABIName = "apcs-gnu"; + break; + + case llvm::Triple::Linux: + ABIName = "aapcs-linux"; + break; + } + } + CmdArgs.push_back("-target-abi"); + CmdArgs.push_back(ABIName); + + // Set the CPU based on -march= and -mcpu=. + CmdArgs.push_back(Args.MakeArgString("-mcpu=" + getARMTargetCPU(Args))); + + // Select the float ABI as determined by -msoft-float, -mhard-float, and + // -mfloat-abi=. + llvm::StringRef FloatABI; + if (Arg *A = Args.getLastArg(options::OPT_msoft_float, + options::OPT_mhard_float, + options::OPT_mfloat_abi_EQ)) { + if (A->getOption().matches(options::OPT_msoft_float)) + FloatABI = "soft"; + else if (A->getOption().matches(options::OPT_mhard_float)) + FloatABI = "hard"; + else { + FloatABI = A->getValue(Args); + if (FloatABI != "soft" && FloatABI != "softfp" && FloatABI != "hard") { + D.Diag(clang::diag::err_drv_invalid_mfloat_abi) + << A->getAsString(Args); + FloatABI = "soft"; + } + } + } + + // If unspecified, choose the default based on the platform. + if (FloatABI.empty()) { + // FIXME: This is wrong for non-Darwin, we don't have a mechanism yet for + // distinguishing things like linux-eabi vs linux-elf. + switch (getToolChain().getTriple().getOS()) { + case llvm::Triple::Darwin: { + // Darwin defaults to "softfp" for v6 and v7. + // + // FIXME: Factor out an ARM class so we can cache the arch somewhere. + llvm::StringRef ArchName = getLLVMArchSuffixForARM(getARMTargetCPU(Args)); + if (ArchName.startswith("v6") || ArchName.startswith("v7")) + FloatABI = "softfp"; + else + FloatABI = "soft"; + break; + } + + default: + // Assume "soft", but warn the user we are guessing. + FloatABI = "soft"; + D.Diag(clang::diag::warn_drv_assuming_mfloat_abi_is) << "soft"; + break; + } + } + + if (FloatABI == "soft") { + // Floating point operations and argument passing are soft. + // + // FIXME: This changes CPP defines, we need -target-soft-float. + CmdArgs.push_back("-soft-float"); + CmdArgs.push_back("-float-abi=soft"); + } else if (FloatABI == "softfp") { + // Floating point operations are hard, but argument passing is soft. + CmdArgs.push_back("-float-abi=soft"); + } else { + // Floating point operations and argument passing are hard. + assert(FloatABI == "hard" && "Invalid float abi!"); + CmdArgs.push_back("-float-abi=hard"); + } +} + +void Clang::AddX86TargetArgs(const ArgList &Args, + ArgStringList &CmdArgs) const { + // FIXME: This needs to change to use a clang-cc option, and set the attribute + // on functions. + if (!Args.hasFlag(options::OPT_mred_zone, + options::OPT_mno_red_zone, + true) || + Args.hasArg(options::OPT_mkernel) || + Args.hasArg(options::OPT_fapple_kext)) + CmdArgs.push_back("--disable-red-zone"); + + // FIXME: This needs to change to use a clang-cc option, and set the attribute + // on functions. + if (Args.hasFlag(options::OPT_msoft_float, + options::OPT_mno_soft_float, + false)) + CmdArgs.push_back("--no-implicit-float"); + + if (const Arg *A = Args.getLastArg(options::OPT_march_EQ)) { + // FIXME: We may need some translation here from the options gcc takes to + // names the LLVM backend understand? + CmdArgs.push_back("-mcpu"); + CmdArgs.push_back(A->getValue(Args)); + } else { + // Select default CPU. + + // FIXME: Need target hooks. + if (memcmp(getToolChain().getOS().c_str(), "darwin", 6) == 0) { + if (getToolChain().getArchName() == "x86_64") + CmdArgs.push_back("--mcpu=core2"); + else if (getToolChain().getArchName() == "i386") + CmdArgs.push_back("--mcpu=yonah"); + } else { + if (getToolChain().getArchName() == "x86_64") + CmdArgs.push_back("--mcpu=x86-64"); + else if (getToolChain().getArchName() == "i386") + CmdArgs.push_back("--mcpu=pentium4"); + } + } + + // FIXME: Use iterator. + for (ArgList::const_iterator + it = Args.begin(), ie = Args.end(); it != ie; ++it) { + const Arg *A = *it; + if (A->getOption().matches(options::OPT_m_x86_Features_Group)) { + llvm::StringRef Name = A->getOption().getName(); + + // Skip over "-m". + assert(Name.startswith("-m") && "Invalid feature name."); + Name = Name.substr(2); + + bool IsNegative = Name.startswith("no-"); + if (IsNegative) + Name = Name.substr(3); + + A->claim(); + CmdArgs.push_back("-target-feature"); + CmdArgs.push_back(Args.MakeArgString((IsNegative ? "-" : "+") + Name)); + } + } +} + +static bool needsExceptions(const ArgList &Args, types::ID InputType, + const llvm::Triple &Triple) { + if (Arg *A = Args.getLastArg(options::OPT_fexceptions, + options::OPT_fno_exceptions)) { + if (A->getOption().matches(options::OPT_fexceptions)) + return true; + else + return false; + } + switch (InputType) { + case types::TY_CXX: case types::TY_CXXHeader: + case types::TY_PP_CXX: case types::TY_PP_CXXHeader: + case types::TY_ObjCXX: case types::TY_ObjCXXHeader: + case types::TY_PP_ObjCXX: case types::TY_PP_ObjCXXHeader: + return true; + + case types::TY_ObjC: case types::TY_ObjCHeader: + case types::TY_PP_ObjC: case types::TY_PP_ObjCHeader: + if (Args.hasArg(options::OPT_fobjc_nonfragile_abi)) + return true; + if (Triple.getOS() != llvm::Triple::Darwin) + return false; + return (Triple.getDarwinMajorNumber() >= 9 && + Triple.getArch() == llvm::Triple::x86_64); + + default: + return false; + } +} + void Clang::ConstructJob(Compilation &C, const JobAction &JA, Job &Dest, const InputInfo &Output, @@ -193,8 +514,9 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA, assert(Inputs.size() == 1 && "Unable to handle multiple inputs."); CmdArgs.push_back("-triple"); + const char *TripleStr = - Args.MakeArgString(getToolChain().getTripleString().c_str()); + Args.MakeArgString(getLLVMTriple(getToolChain(), Args)); CmdArgs.push_back(TripleStr); if (isa<AnalyzeJobAction>(JA)) { @@ -221,6 +543,8 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA, CmdArgs.push_back("-emit-llvm-bc"); } else if (JA.getType() == types::TY_PP_Asm) { CmdArgs.push_back("-S"); + } else if (JA.getType() == types::TY_AST) { + CmdArgs.push_back("-emit-pch"); } } @@ -238,9 +562,13 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA, CmdArgs.push_back("-static-define"); if (isa<AnalyzeJobAction>(JA)) { + // Enable region store model by default. + CmdArgs.push_back("-analyzer-store=region"); + // Add default argument set. if (!Args.hasArg(options::OPT__analyzer_no_default_checks)) { CmdArgs.push_back("-warn-dead-stores"); + CmdArgs.push_back("-warn-security-syntactic"); CmdArgs.push_back("-checker-cfref"); CmdArgs.push_back("-analyzer-eagerly-assume"); CmdArgs.push_back("-warn-objc-methodsigs"); @@ -259,8 +587,10 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA, // Add -Xanalyzer arguments when running as analyzer. Args.AddAllArgValues(CmdArgs, options::OPT_Xanalyzer); - } - + } + + CheckCodeGenerationOptions(D, Args); + // Perform argument translation for LLVM backend. This // takes some care in reconciling with llvm-gcc. The // issue is that llvm-gcc translates these options based on @@ -308,7 +638,8 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA, if (Args.hasArg(options::OPT_ftime_report)) CmdArgs.push_back("--time-passes"); // FIXME: Set --enable-unsafe-fp-math. - if (!Args.hasArg(options::OPT_fomit_frame_pointer)) + if (Args.hasFlag(options::OPT_fno_omit_frame_pointer, + options::OPT_fomit_frame_pointer)) CmdArgs.push_back("--disable-fp-elim"); if (!Args.hasFlag(options::OPT_fzero_initialized_in_bss, options::OPT_fno_zero_initialized_in_bss, @@ -322,71 +653,43 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA, CmdArgs.push_back("--debug-pass=Arguments"); // FIXME: set --inline-threshhold=50 if (optimize_size || optimize // < 3) - if (Args.hasFlag(options::OPT_funwind_tables, - options::OPT_fno_unwind_tables, - (getToolChain().IsUnwindTablesDefault() && - !Args.hasArg(options::OPT_mkernel)))) + + // This is a coarse approximation of what llvm-gcc actually does, both + // -fasynchronous-unwind-tables and -fnon-call-exceptions interact in more + // complicated ways. + bool AsynchronousUnwindTables = + Args.hasFlag(options::OPT_fasynchronous_unwind_tables, + options::OPT_fno_asynchronous_unwind_tables, + getToolChain().IsUnwindTablesDefault() && + !Args.hasArg(options::OPT_mkernel)); + if (Args.hasFlag(options::OPT_funwind_tables, options::OPT_fno_unwind_tables, + AsynchronousUnwindTables)) CmdArgs.push_back("--unwind-tables=1"); else CmdArgs.push_back("--unwind-tables=0"); - if (!Args.hasFlag(options::OPT_mred_zone, - options::OPT_mno_red_zone, - true) || - Args.hasArg(options::OPT_mkernel) || - Args.hasArg(options::OPT_fapple_kext)) - CmdArgs.push_back("--disable-red-zone"); - if (Args.hasFlag(options::OPT_msoft_float, - options::OPT_mno_soft_float, - false)) - CmdArgs.push_back("--no-implicit-float"); // FIXME: Handle -mtune=. (void) Args.hasArg(options::OPT_mtune_EQ); - if (const Arg *A = Args.getLastArg(options::OPT_march_EQ)) { - // FIXME: We may need some translation here from the options gcc takes to - // names the LLVM backend understand? - CmdArgs.push_back("-mcpu"); + if (Arg *A = Args.getLastArg(options::OPT_mcmodel_EQ)) { + CmdArgs.push_back("-code-model"); CmdArgs.push_back(A->getValue(Args)); - } else { - // Select default CPU. - - // FIXME: Need target hooks. - if (memcmp(getToolChain().getOS().c_str(), "darwin", 6) == 0) { - if (getToolChain().getArchName() == "x86_64") - CmdArgs.push_back("--mcpu=core2"); - else if (getToolChain().getArchName() == "i386") - CmdArgs.push_back("--mcpu=yonah"); - } else { - if (getToolChain().getArchName() == "x86_64") - CmdArgs.push_back("--mcpu=x86-64"); - else if (getToolChain().getArchName() == "i386") - CmdArgs.push_back("--mcpu=pentium4"); - } } - // FIXME: Use iterator. - for (ArgList::const_iterator - it = Args.begin(), ie = Args.end(); it != ie; ++it) { - const Arg *A = *it; - if (A->getOption().matches(options::OPT_m_x86_Features_Group)) { - const char *Name = A->getOption().getName(); + // Add target specific cpu and features flags. + switch(getToolChain().getTriple().getArch()) { + default: + break; - // Skip over "-m". - assert(Name[0] == '-' && Name[1] == 'm' && "Invalid feature name."); - Name += 2; - - bool IsNegative = memcmp(Name, "no-", 3) == 0; - if (IsNegative) - Name += 3; + case llvm::Triple::arm: + case llvm::Triple::thumb: + AddARMTargetArgs(Args, CmdArgs); + break; - A->claim(); - CmdArgs.push_back("-target-feature"); - CmdArgs.push_back(MakeFormattedString(Args, - llvm::format("%c%s", - IsNegative ? '-' : '+', - Name))); - } + case llvm::Triple::x86: + case llvm::Triple::x86_64: + AddX86TargetArgs(Args, CmdArgs); + break; } if (Args.hasFlag(options::OPT_fmath_errno, @@ -415,7 +718,7 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA, Args.AddLastArg(CmdArgs, options::OPT_P); Args.AddLastArg(CmdArgs, options::OPT_mmacosx_version_min_EQ); Args.AddLastArg(CmdArgs, options::OPT_miphoneos_version_min_EQ); - Args.AddLastArg(CmdArgs, options::OPT_print_ivar_layout); + Args.AddLastArg(CmdArgs, options::OPT_print_ivar_layout); // Special case debug options to only pass -g to clang. This is // wrong. @@ -423,6 +726,7 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA, CmdArgs.push_back("-g"); Args.AddLastArg(CmdArgs, options::OPT_nostdinc); + Args.AddLastArg(CmdArgs, options::OPT_nostdclanginc); Args.AddLastArg(CmdArgs, options::OPT_isysroot); @@ -434,13 +738,13 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA, if (types::getPreprocessedType(InputType) != types::TY_INVALID) AddPreprocessingOptions(D, Args, CmdArgs, Output, Inputs); - // Manually translate -O to -O1 and -O4 to -O3; let clang reject + // Manually translate -O to -O2 and -O4 to -O3; let clang reject // others. if (Arg *A = Args.getLastArg(options::OPT_O_Group)) { if (A->getOption().getId() == options::OPT_O4) CmdArgs.push_back("-O3"); else if (A->getValue(Args)[0] == '\0') - CmdArgs.push_back("-O1"); + CmdArgs.push_back("-O2"); else A->render(Args, CmdArgs); } @@ -474,9 +778,16 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA, CmdArgs.push_back(A->getValue(Args)); } + if (Args.hasArg(options::OPT__relocatable_pch, true)) + CmdArgs.push_back("--relocatable-pch"); + + if (Arg *A = Args.getLastArg(options::OPT_fconstant_string_class_EQ)) { + CmdArgs.push_back("-fconstant-string-class"); + CmdArgs.push_back(A->getValue(Args)); + } + // Forward -f options which we can pass directly. Args.AddLastArg(CmdArgs, options::OPT_femit_all_decls); - Args.AddLastArg(CmdArgs, options::OPT_fexceptions); Args.AddLastArg(CmdArgs, options::OPT_ffreestanding); Args.AddLastArg(CmdArgs, options::OPT_fheinous_gnu_extensions); Args.AddLastArg(CmdArgs, options::OPT_fgnu_runtime); @@ -498,6 +809,8 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA, Args.AddLastArg(CmdArgs, options::OPT_fvisibility_EQ); Args.AddLastArg(CmdArgs, options::OPT_fwritable_strings); + Args.AddLastArg(CmdArgs, options::OPT_pthread); + // Forward stack protector flags. if (Arg *A = Args.getLastArg(options::OPT_fno_stack_protector, options::OPT_fstack_protector_all, @@ -526,6 +839,15 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA, CmdArgs.push_back("-fblocks=0"); } + if (needsExceptions(Args, InputType, getToolChain().getTriple())) + CmdArgs.push_back("-fexceptions"); + else + CmdArgs.push_back("-fexceptions=0"); + + // -frtti is default, only pass non-default. + if (!Args.hasFlag(options::OPT_frtti, options::OPT_fno_rtti)) + CmdArgs.push_back("-frtti=0"); + // -fsigned-char/-funsigned-char default varies depending on platform; only // pass if specified. if (Arg *A = Args.getLastArg(options::OPT_fsigned_char, @@ -556,18 +878,18 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA, // -fsigned-bitfields is default, and clang doesn't yet support // --funsigned-bitfields. - if (!Args.hasFlag(options::OPT_fsigned_bitfields, + if (!Args.hasFlag(options::OPT_fsigned_bitfields, options::OPT_funsigned_bitfields)) D.Diag(clang::diag::warn_drv_clang_unsupported) << Args.getLastArg(options::OPT_funsigned_bitfields)->getAsString(Args); // -fdiagnostics-fixit-info is default, only pass non-default. - if (!Args.hasFlag(options::OPT_fdiagnostics_fixit_info, + if (!Args.hasFlag(options::OPT_fdiagnostics_fixit_info, options::OPT_fno_diagnostics_fixit_info)) CmdArgs.push_back("-fno-diagnostics-fixit-info"); // Enable -fdiagnostics-show-option by default. - if (Args.hasFlag(options::OPT_fdiagnostics_show_option, + if (Args.hasFlag(options::OPT_fdiagnostics_show_option, options::OPT_fno_diagnostics_show_option)) CmdArgs.push_back("-fdiagnostics-show-option"); if (!Args.hasFlag(options::OPT_fcolor_diagnostics, @@ -579,7 +901,7 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA, // -fdollars-in-identifiers default varies depending on platform and // language; only pass if specified. - if (Arg *A = Args.getLastArg(options::OPT_fdollars_in_identifiers, + if (Arg *A = Args.getLastArg(options::OPT_fdollars_in_identifiers, options::OPT_fno_dollars_in_identifiers)) { if (A->getOption().matches(options::OPT_fdollars_in_identifiers)) CmdArgs.push_back("-fdollars-in-identifiers=1"); @@ -589,12 +911,30 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA, // -funit-at-a-time is default, and we don't support -fno-unit-at-a-time for // practical purposes. - if (Arg *A = Args.getLastArg(options::OPT_funit_at_a_time, + if (Arg *A = Args.getLastArg(options::OPT_funit_at_a_time, options::OPT_fno_unit_at_a_time)) { if (A->getOption().matches(options::OPT_fno_unit_at_a_time)) - D.Diag(clang::diag::err_drv_clang_unsupported) << A->getAsString(Args); + D.Diag(clang::diag::warn_drv_clang_unsupported) << A->getAsString(Args); } - + + // Default to -fno-builtin-str{cat,cpy} on Darwin for ARM. + // + // FIXME: This is disabled until clang-cc supports -fno-builtin-foo. PR4941. +#if 0 + if (getToolChain().getTriple().getOS() == llvm::Triple::Darwin && + (getToolChain().getTriple().getArch() == llvm::Triple::arm || + getToolChain().getTriple().getArch() == llvm::Triple::thumb)) { + if (!Args.hasArg(options::OPT_fbuiltin_strcat)) + CmdArgs.push_back("-fno-builtin-strcat"); + if (!Args.hasArg(options::OPT_fbuiltin_strcpy)) + CmdArgs.push_back("-fno-builtin-strcpy"); + } +#endif + + if (Arg *A = Args.getLastArg(options::OPT_traditional, + options::OPT_traditional_cpp)) + D.Diag(clang::diag::err_drv_clang_unsupported) << A->getAsString(Args); + Args.AddLastArg(CmdArgs, options::OPT_dM); Args.AddLastArg(CmdArgs, options::OPT_dD); @@ -627,7 +967,7 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA, } const char *Exec = - Args.MakeArgString(getToolChain().GetProgramPath(C, "clang-cc").c_str()); + Args.MakeArgString(getToolChain().GetProgramPath(C, "clang-cc")); Dest.addCommand(new Command(JA, Exec, CmdArgs)); // Explicitly warn that these options are unsupported, even though @@ -699,7 +1039,7 @@ void gcc::Common::ConstructJob(Compilation &C, const JobAction &JA, else if (Arch == "powerpc64") CmdArgs.push_back("ppc64"); else - CmdArgs.push_back(Args.MakeArgString(Arch.c_str())); + CmdArgs.push_back(Args.MakeArgString(Arch)); } // Try to force gcc to match the tool chain we want, if we recognize @@ -736,10 +1076,13 @@ void gcc::Common::ConstructJob(Compilation &C, const JobAction &JA, it = Inputs.begin(), ie = Inputs.end(); it != ie; ++it) { const InputInfo &II = *it; - // Don't try to pass LLVM inputs to a generic gcc. + // Don't try to pass LLVM or AST inputs to a generic gcc. if (II.getType() == types::TY_LLVMBC) D.Diag(clang::diag::err_drv_no_linker_llvm_support) - << getToolChain().getTripleString().c_str(); + << getToolChain().getTripleString(); + else if (II.getType() == types::TY_AST) + D.Diag(clang::diag::err_drv_no_ast_support) + << getToolChain().getTripleString(); if (types::canTypeBeUserSpecified(II.getType())) { CmdArgs.push_back("-x"); @@ -758,7 +1101,7 @@ void gcc::Common::ConstructJob(Compilation &C, const JobAction &JA, const char *GCCName = getToolChain().getHost().getDriver().CCCGenericGCCName.c_str(); const char *Exec = - Args.MakeArgString(getToolChain().GetProgramPath(C, GCCName).c_str()); + Args.MakeArgString(getToolChain().GetProgramPath(C, GCCName)); Dest.addCommand(new Command(JA, Exec, CmdArgs)); } @@ -805,7 +1148,7 @@ const char *darwin::CC1::getCC1Name(types::ID Type) const { const char *darwin::CC1::getBaseInputName(const ArgList &Args, const InputInfoList &Inputs) { llvm::sys::Path P(Inputs[0].getBaseInput()); - return Args.MakeArgString(P.getLast().c_str()); + return Args.MakeArgString(P.getLast()); } const char *darwin::CC1::getBaseInputStem(const ArgList &Args, @@ -813,7 +1156,7 @@ const char *darwin::CC1::getBaseInputStem(const ArgList &Args, const char *Str = getBaseInputName(Args, Inputs); if (const char *End = strchr(Str, '.')) - return Args.MakeArgString(std::string(Str, End).c_str()); + return Args.MakeArgString(std::string(Str, End)); return Str; } @@ -831,31 +1174,32 @@ darwin::CC1::getDependencyFileName(const ArgList &Args, } else Res = darwin::CC1::getBaseInputStem(Args, Inputs); - return Args.MakeArgString((Res + ".d").c_str()); + return Args.MakeArgString(Res + ".d"); } void darwin::CC1::AddCC1Args(const ArgList &Args, ArgStringList &CmdArgs) const { - // Derived from cc1 spec. + const Driver &D = getToolChain().getHost().getDriver(); + + CheckCodeGenerationOptions(D, Args); - // FIXME: -fapple-kext seems to disable this too. Investigate. + // Derived from cc1 spec. if (!Args.hasArg(options::OPT_mkernel) && !Args.hasArg(options::OPT_static) && !Args.hasArg(options::OPT_mdynamic_no_pic)) CmdArgs.push_back("-fPIC"); + if (getToolChain().getTriple().getArch() == llvm::Triple::arm || + getToolChain().getTriple().getArch() == llvm::Triple::thumb) { + if (!Args.hasArg(options::OPT_fbuiltin_strcat)) + CmdArgs.push_back("-fno-builtin-strcat"); + if (!Args.hasArg(options::OPT_fbuiltin_strcpy)) + CmdArgs.push_back("-fno-builtin-strcpy"); + } + // gcc has some code here to deal with when no -mmacosx-version-min // and no -miphoneos-version-min is present, but this never happens // due to tool chain specific argument translation. - // FIXME: Remove mthumb - // FIXME: Remove mno-thumb - // FIXME: Remove faltivec - // FIXME: Remove mno-fused-madd - // FIXME: Remove mlong-branch - // FIXME: Remove mlongcall - // FIXME: Remove mcpu=G4 - // FIXME: Remove mcpu=G5 - if (Args.hasArg(options::OPT_g_Flag) && !Args.hasArg(options::OPT_fno_eliminate_unused_debug_symbols)) CmdArgs.push_back("-feliminate-unused-debug-symbols"); @@ -924,7 +1268,28 @@ void darwin::CC1::AddCC1OptionsArgs(const ArgList &Args, ArgStringList &CmdArgs, Args.AddLastArg(CmdArgs, options::OPT_p); // The driver treats -fsyntax-only specially. - Args.AddAllArgs(CmdArgs, options::OPT_f_Group, options::OPT_fsyntax_only); + if (getToolChain().getTriple().getArch() == llvm::Triple::arm || + getToolChain().getTriple().getArch() == llvm::Triple::thumb) { + // Removes -fbuiltin-str{cat,cpy}; these aren't recognized by cc1 but are + // used to inhibit the default -fno-builtin-str{cat,cpy}. + // + // FIXME: Should we grow a better way to deal with "removing" args? + // + // FIXME: Use iterator. + for (ArgList::const_iterator it = Args.begin(), + ie = Args.end(); it != ie; ++it) { + const Arg *A = *it; + if (A->getOption().matches(options::OPT_f_Group) || + A->getOption().matches(options::OPT_fsyntax_only)) { + if (!A->getOption().matches(options::OPT_fbuiltin_strcat) && + !A->getOption().matches(options::OPT_fbuiltin_strcpy)) { + A->claim(); + A->render(Args, CmdArgs); + } + } + } + } else + Args.AddAllArgs(CmdArgs, options::OPT_f_Group, options::OPT_fsyntax_only); Args.AddAllArgs(CmdArgs, options::OPT_undef); if (Args.hasArg(options::OPT_Qn)) @@ -995,18 +1360,15 @@ void darwin::CC1::AddCPPOptionsArgs(const ArgList &Args, ArgStringList &CmdArgs, void darwin::CC1::AddCPPUniqueOptionsArgs(const ArgList &Args, ArgStringList &CmdArgs, - const InputInfoList &Inputs) const -{ + const InputInfoList &Inputs) const { const Driver &D = getToolChain().getHost().getDriver(); + CheckPreprocessingOptions(D, Args); + // Derived from cpp_unique_options. - Arg *A; - if ((A = Args.getLastArg(options::OPT_C)) || - (A = Args.getLastArg(options::OPT_CC))) { - if (!Args.hasArg(options::OPT_E)) - D.Diag(clang::diag::err_drv_argument_only_allowed_with) - << A->getAsString(Args) << "-E"; - } + // -{C,CC} only with -E is checked in CheckPreprocessingOptions(). + Args.AddLastArg(CmdArgs, options::OPT_C); + Args.AddLastArg(CmdArgs, options::OPT_CC); if (!Args.hasArg(options::OPT_Q)) CmdArgs.push_back("-quiet"); Args.AddAllArgs(CmdArgs, options::OPT_nostdinc); @@ -1111,7 +1473,6 @@ void darwin::Preprocess::ConstructJob(Compilation &C, const JobAction &JA, CmdArgs.push_back("-E"); if (Args.hasArg(options::OPT_traditional) || - Args.hasArg(options::OPT_ftraditional) || Args.hasArg(options::OPT_traditional_cpp)) CmdArgs.push_back("-traditional-cpp"); @@ -1134,7 +1495,7 @@ void darwin::Preprocess::ConstructJob(Compilation &C, const JobAction &JA, const char *CC1Name = getCC1Name(Inputs[0].getType()); const char *Exec = - Args.MakeArgString(getToolChain().GetProgramPath(C, CC1Name).c_str()); + Args.MakeArgString(getToolChain().GetProgramPath(C, CC1Name)); Dest.addCommand(new Command(JA, Exec, CmdArgs)); } @@ -1150,8 +1511,7 @@ void darwin::Compile::ConstructJob(Compilation &C, const JobAction &JA, types::ID InputType = Inputs[0].getType(); const Arg *A; - if ((A = Args.getLastArg(options::OPT_traditional)) || - (A = Args.getLastArg(options::OPT_ftraditional))) + if ((A = Args.getLastArg(options::OPT_traditional))) D.Diag(clang::diag::err_drv_argument_only_allowed_with) << A->getAsString(Args) << "-E"; @@ -1159,6 +1519,9 @@ void darwin::Compile::ConstructJob(Compilation &C, const JobAction &JA, CmdArgs.push_back("-emit-llvm"); else if (Output.getType() == types::TY_LLVMBC) CmdArgs.push_back("-emit-llvm-bc"); + else if (Output.getType() == types::TY_AST) + D.Diag(clang::diag::err_drv_no_ast_support) + << getToolChain().getTripleString(); ArgStringList OutputArgs; if (Output.getType() != types::TY_PCH) { @@ -1187,13 +1550,17 @@ void darwin::Compile::ConstructJob(Compilation &C, const JobAction &JA, } else { CmdArgs.push_back("-fpreprocessed"); - // FIXME: There is a spec command to remove - // -fpredictive-compilation args here. Investigate. - for (InputInfoList::const_iterator it = Inputs.begin(), ie = Inputs.end(); it != ie; ++it) { const InputInfo &II = *it; + // Reject AST inputs. + if (II.getType() == types::TY_AST) { + D.Diag(clang::diag::err_drv_no_ast_support) + << getToolChain().getTripleString(); + return; + } + if (II.isPipe()) CmdArgs.push_back("-"); else @@ -1222,7 +1589,7 @@ void darwin::Compile::ConstructJob(Compilation &C, const JobAction &JA, const char *CC1Name = getCC1Name(Inputs[0].getType()); const char *Exec = - Args.MakeArgString(getToolChain().GetProgramPath(C, CC1Name).c_str()); + Args.MakeArgString(getToolChain().GetProgramPath(C, CC1Name)); Dest.addCommand(new Command(JA, Exec, CmdArgs)); } @@ -1248,14 +1615,16 @@ void darwin::Assemble::ConstructJob(Compilation &C, const JobAction &JA, } // Derived from asm spec. - CmdArgs.push_back("-arch"); - CmdArgs.push_back(Args.MakeArgString(getToolChain().getArchName().c_str())); + AddDarwinArch(Args, CmdArgs); + + if (!getDarwinToolChain().isIPhoneOS() || + Args.hasArg(options::OPT_force__cpusubtype__ALL)) + CmdArgs.push_back("-force_cpusubtype_ALL"); - CmdArgs.push_back("-force_cpusubtype_ALL"); - if ((Args.hasArg(options::OPT_mkernel) || + if (getToolChain().getTriple().getArch() != llvm::Triple::x86_64 && + (Args.hasArg(options::OPT_mkernel) || Args.hasArg(options::OPT_static) || - Args.hasArg(options::OPT_fapple_kext)) && - !Args.hasArg(options::OPT_dynamic)) + Args.hasArg(options::OPT_fapple_kext))) CmdArgs.push_back("-static"); Args.AddAllArgValues(CmdArgs, options::OPT_Wa_COMMA, @@ -1275,7 +1644,7 @@ void darwin::Assemble::ConstructJob(Compilation &C, const JobAction &JA, // asm_final spec is empty. const char *Exec = - Args.MakeArgString(getToolChain().GetProgramPath(C, "as").c_str()); + Args.MakeArgString(getToolChain().GetProgramPath(C, "as")); Dest.addCommand(new Command(JA, Exec, CmdArgs)); } @@ -1304,33 +1673,84 @@ static bool isSourceSuffix(const char *Str) { } } -static bool isMacosxVersionLT(unsigned (&A)[3], unsigned (&B)[3]) { - for (unsigned i=0; i < 3; ++i) { - if (A[i] > B[i]) return false; - if (A[i] < B[i]) return true; - } - return false; -} +// FIXME: Can we tablegen this? +static const char *GetArmArchForMArch(llvm::StringRef Value) { + if (Value == "armv6k") + return "armv6"; + + if (Value == "armv5tej") + return "armv5"; + + if (Value == "xscale") + return "xscale"; -static bool isMacosxVersionLT(unsigned (&A)[3], - unsigned V0, unsigned V1=0, unsigned V2=0) { - unsigned B[3] = { V0, V1, V2 }; - return isMacosxVersionLT(A, B); + if (Value == "armv4t") + return "armv4t"; + + if (Value == "armv7" || Value == "armv7-a" || Value == "armv7-r" || + Value == "armv7-m" || Value == "armv7a" || Value == "armv7r" || + Value == "armv7m") + return "armv7"; + + return 0; } -const toolchains::Darwin_X86 &darwin::Link::getDarwinToolChain() const { - return reinterpret_cast<const toolchains::Darwin_X86&>(getToolChain()); +// FIXME: Can we tablegen this? +static const char *GetArmArchForMCpu(llvm::StringRef Value) { + if (Value == "arm10tdmi" || Value == "arm1020t" || Value == "arm9e" || + Value == "arm946e-s" || Value == "arm966e-s" || + Value == "arm968e-s" || Value == "arm10e" || + Value == "arm1020e" || Value == "arm1022e" || Value == "arm926ej-s" || + Value == "arm1026ej-s") + return "armv5"; + + if (Value == "xscale") + return "xscale"; + + if (Value == "arm1136j-s" || Value == "arm1136jf-s" || + Value == "arm1176jz-s" || Value == "arm1176jzf-s") + return "armv6"; + + if (Value == "cortex-a8" || Value == "cortex-r4" || Value == "cortex-m3") + return "armv7"; + + return 0; } -void darwin::Link::AddDarwinArch(const ArgList &Args, - ArgStringList &CmdArgs) const { +void darwin::DarwinTool::AddDarwinArch(const ArgList &Args, + ArgStringList &CmdArgs) const { // Derived from darwin_arch spec. CmdArgs.push_back("-arch"); - CmdArgs.push_back(Args.MakeArgString(getToolChain().getArchName().c_str())); + + switch (getToolChain().getTriple().getArch()) { + default: + CmdArgs.push_back(Args.MakeArgString(getToolChain().getArchName())); + break; + + case llvm::Triple::arm: { + if (const Arg *A = Args.getLastArg(options::OPT_march_EQ)) { + if (const char *Arch = GetArmArchForMArch(A->getValue(Args))) { + CmdArgs.push_back(Arch); + return; + } + } + + if (const Arg *A = Args.getLastArg(options::OPT_mcpu_EQ)) { + if (const char *Arch = GetArmArchForMCpu(A->getValue(Args))) { + CmdArgs.push_back(Arch); + return; + } + } + + CmdArgs.push_back("arm"); + CmdArgs.push_back("-force_cpusubtype_ALL"); + return; + } + } } -void darwin::Link::AddDarwinSubArch(const ArgList &Args, - ArgStringList &CmdArgs) const { +void darwin::DarwinTool::AddDarwinSubArch(const ArgList &Args, + ArgStringList &CmdArgs) const { // Derived from darwin_subarch spec, not sure what the distinction // exists for but at least for this chain it is the same. AddDarwinArch(Args, CmdArgs); @@ -1401,6 +1821,8 @@ void darwin::Link::AddLinkArgs(const ArgList &Args, Args.AddLastArg(CmdArgs, options::OPT_all__load); Args.AddAllArgs(CmdArgs, options::OPT_allowable__client); Args.AddLastArg(CmdArgs, options::OPT_bind__at__load); + if (getDarwinToolChain().isIPhoneOS()) + Args.AddLastArg(CmdArgs, options::OPT_arch__errors__fatal); Args.AddLastArg(CmdArgs, options::OPT_dead__strip); Args.AddLastArg(CmdArgs, options::OPT_no__dead__strip__inits__and__terms); Args.AddAllArgs(CmdArgs, options::OPT_dylib__file); @@ -1411,22 +1833,22 @@ void darwin::Link::AddLinkArgs(const ArgList &Args, Args.AddAllArgs(CmdArgs, options::OPT_image__base); Args.AddAllArgs(CmdArgs, options::OPT_init); - if (!Args.hasArg(options::OPT_mmacosx_version_min_EQ)) { - if (!Args.hasArg(options::OPT_miphoneos_version_min_EQ)) { - // FIXME: I don't understand what is going on here. This is - // supposed to come from darwin_ld_minversion, but gcc doesn't - // seem to be following that; it must be getting overridden - // somewhere. + if (!Args.hasArg(options::OPT_mmacosx_version_min_EQ) && + !Args.hasArg(options::OPT_miphoneos_version_min_EQ)) { + // Add default version min. + if (!getDarwinToolChain().isIPhoneOS()) { CmdArgs.push_back("-macosx_version_min"); CmdArgs.push_back(getDarwinToolChain().getMacosxVersionStr()); + } else { + CmdArgs.push_back("-iphoneos_version_min"); + CmdArgs.push_back(getDarwinToolChain().getIPhoneOSVersionStr()); } - } else { - // Adding all arguments doesn't make sense here but this is what - // gcc does. - Args.AddAllArgsTranslated(CmdArgs, options::OPT_mmacosx_version_min_EQ, - "-macosx_version_min"); } + // Adding all arguments doesn't make sense here but this is what + // gcc does. + Args.AddAllArgsTranslated(CmdArgs, options::OPT_mmacosx_version_min_EQ, + "-macosx_version_min"); Args.AddAllArgsTranslated(CmdArgs, options::OPT_miphoneos_version_min_EQ, "-iphoneos_version_min"); Args.AddLastArg(CmdArgs, options::OPT_nomultidefs); @@ -1454,14 +1876,22 @@ void darwin::Link::AddLinkArgs(const ArgList &Args, Args.AddAllArgs(CmdArgs, options::OPT_seg__addr__table__filename); Args.AddAllArgs(CmdArgs, options::OPT_sub__library); Args.AddAllArgs(CmdArgs, options::OPT_sub__umbrella); + Args.AddAllArgsTranslated(CmdArgs, options::OPT_isysroot, "-syslibroot"); + if (getDarwinToolChain().isIPhoneOS()) { + if (!Args.hasArg(options::OPT_isysroot)) { + CmdArgs.push_back("-syslibroot"); + CmdArgs.push_back("/Developer/SDKs/Extra"); + } + } + Args.AddLastArg(CmdArgs, options::OPT_twolevel__namespace); Args.AddLastArg(CmdArgs, options::OPT_twolevel__namespace__hints); Args.AddAllArgs(CmdArgs, options::OPT_umbrella); Args.AddAllArgs(CmdArgs, options::OPT_undefined); Args.AddAllArgs(CmdArgs, options::OPT_unexported__symbols__list); - Args.AddAllArgs(CmdArgs, options::OPT_weak__reference__mismatches); + Args.AddAllArgs(CmdArgs, options::OPT_weak__reference__mismatches); if (!Args.hasArg(options::OPT_weak__reference__mismatches)) { CmdArgs.push_back("-weak_reference_mismatches"); CmdArgs.push_back("non-weak"); @@ -1490,20 +1920,16 @@ void darwin::Link::ConstructJob(Compilation &C, const JobAction &JA, const ArgList &Args, const char *LinkingOutput) const { assert(Output.getType() == types::TY_Image && "Invalid linker output type."); + // The logic here is derived from gcc's behavior; most of which // comes from specs (starting with link_command). Consult gcc for // more information. - - // FIXME: The spec references -fdump= which seems to have - // disappeared? - ArgStringList CmdArgs; // I'm not sure why this particular decomposition exists in gcc, but // we follow suite for ease of comparison. AddLinkArgs(Args, CmdArgs); - // FIXME: gcc has %{x} in here. How could this ever happen? Cruft? Args.AddAllArgs(CmdArgs, options::OPT_d_Flag); Args.AddAllArgs(CmdArgs, options::OPT_s); Args.AddAllArgs(CmdArgs, options::OPT_t); @@ -1514,28 +1940,12 @@ void darwin::Link::ConstructJob(Compilation &C, const JobAction &JA, Args.AddAllArgs(CmdArgs, options::OPT_m_Separate); Args.AddAllArgs(CmdArgs, options::OPT_r); - // FIXME: This is just being pedantically bug compatible, gcc - // doesn't *mean* to forward this, it just does (yay for pattern - // matching). It doesn't work, of course. - Args.AddAllArgs(CmdArgs, options::OPT_object); - CmdArgs.push_back("-o"); CmdArgs.push_back(Output.getFilename()); - unsigned MacosxVersion[3]; - if (Arg *A = Args.getLastArg(options::OPT_mmacosx_version_min_EQ)) { - bool HadExtra; - if (!Driver::GetReleaseVersion(A->getValue(Args), MacosxVersion[0], - MacosxVersion[1], MacosxVersion[2], - HadExtra) || - HadExtra) { - const Driver &D = getToolChain().getHost().getDriver(); - D.Diag(clang::diag::err_drv_invalid_version_number) - << A->getAsString(Args); - } - } else { - getDarwinToolChain().getMacosxVersion(MacosxVersion); - } + + unsigned MacosxVersionMin[3]; + getDarwinToolChain().getMacosxVersionMin(Args, MacosxVersionMin); if (!Args.hasArg(options::OPT_A) && !Args.hasArg(options::OPT_nostdlib) && @@ -1543,15 +1953,15 @@ void darwin::Link::ConstructJob(Compilation &C, const JobAction &JA, // Derived from startfile spec. if (Args.hasArg(options::OPT_dynamiclib)) { // Derived from darwin_dylib1 spec. - if (isMacosxVersionLT(MacosxVersion, 10, 5)) + if (getDarwinToolChain().isMacosxVersionLT(MacosxVersionMin, 10, 5)) CmdArgs.push_back("-ldylib1.o"); - else if (isMacosxVersionLT(MacosxVersion, 10, 6)) + else if (getDarwinToolChain().isMacosxVersionLT(MacosxVersionMin, 10, 6)) CmdArgs.push_back("-ldylib1.10.5.o"); } else { if (Args.hasArg(options::OPT_bundle)) { if (!Args.hasArg(options::OPT_static)) { // Derived from darwin_bundle1 spec. - if (isMacosxVersionLT(MacosxVersion, 10, 6)) + if (getDarwinToolChain().isMacosxVersionLT(MacosxVersionMin, 10, 6)) CmdArgs.push_back("-lbundle1.o"); } } else { @@ -1572,9 +1982,13 @@ void darwin::Link::ConstructJob(Compilation &C, const JobAction &JA, CmdArgs.push_back("-lcrt0.o"); } else { // Derived from darwin_crt1 spec. - if (isMacosxVersionLT(MacosxVersion, 10, 5)) + if (getDarwinToolChain().isIPhoneOS()) { + CmdArgs.push_back("-lcrt1.o"); + } else if (getDarwinToolChain().isMacosxVersionLT(MacosxVersionMin, + 10, 5)) CmdArgs.push_back("-lcrt1.o"); - else if (isMacosxVersionLT(MacosxVersion, 10, 6)) + else if (getDarwinToolChain().isMacosxVersionLT(MacosxVersionMin, + 10, 6)) CmdArgs.push_back("-lcrt1.10.5.o"); else CmdArgs.push_back("-lcrt1.10.6.o"); @@ -1587,9 +2001,10 @@ void darwin::Link::ConstructJob(Compilation &C, const JobAction &JA, if (Args.hasArg(options::OPT_shared_libgcc) && !Args.hasArg(options::OPT_miphoneos_version_min_EQ) && - isMacosxVersionLT(MacosxVersion, 10, 5)) { - const char *Str = getToolChain().GetFilePath(C, "crt3.o").c_str(); - CmdArgs.push_back(Args.MakeArgString(Str)); + getDarwinToolChain().isMacosxVersionLT(MacosxVersionMin, 10, 5)) { + const char *Str = + Args.MakeArgString(getToolChain().GetFilePath(C, "crt3.o")); + CmdArgs.push_back(Str); } } @@ -1599,26 +2014,7 @@ void darwin::Link::ConstructJob(Compilation &C, const JobAction &JA, // This is more complicated in gcc... CmdArgs.push_back("-lgomp"); - // FIXME: Derive these correctly. - const char *TCDir = getDarwinToolChain().getToolChainDir().c_str(); - if (getToolChain().getArchName() == "x86_64") { - CmdArgs.push_back(MakeFormattedString(Args, - llvm::format("-L/usr/lib/gcc/%s/x86_64", TCDir))); - // Intentionally duplicated for (temporary) gcc bug compatibility. - CmdArgs.push_back(MakeFormattedString(Args, - llvm::format("-L/usr/lib/gcc/%s/x86_64", TCDir))); - } - CmdArgs.push_back(MakeFormattedString(Args, - llvm::format("-L/usr/lib/%s", TCDir))); - CmdArgs.push_back(MakeFormattedString(Args, - llvm::format("-L/usr/lib/gcc/%s", TCDir))); - // Intentionally duplicated for (temporary) gcc bug compatibility. - CmdArgs.push_back(MakeFormattedString(Args, - llvm::format("-L/usr/lib/gcc/%s", TCDir))); - CmdArgs.push_back(MakeFormattedString(Args, - llvm::format("-L/usr/lib/gcc/%s/../../../%s", TCDir, TCDir))); - CmdArgs.push_back(MakeFormattedString(Args, - llvm::format("-L/usr/lib/gcc/%s/../../..", TCDir))); + getDarwinToolChain().AddLinkSearchPathArgs(Args, CmdArgs); for (InputInfoList::const_iterator it = Inputs.begin(), ie = Inputs.end(); it != ie; ++it) { @@ -1653,40 +2049,8 @@ void darwin::Link::ConstructJob(Compilation &C, const JobAction &JA, // link_ssp spec is empty. - // Derived from libgcc and lib specs but refactored. - if (Args.hasArg(options::OPT_static)) { - CmdArgs.push_back("-lgcc_static"); - } else { - if (Args.hasArg(options::OPT_static_libgcc)) { - CmdArgs.push_back("-lgcc_eh"); - } else if (Args.hasArg(options::OPT_miphoneos_version_min_EQ)) { - // Derived from darwin_iphoneos_libgcc spec. - CmdArgs.push_back("-lgcc_s.10.5"); - } else if (Args.hasArg(options::OPT_shared_libgcc) || - Args.hasArg(options::OPT_fexceptions) || - Args.hasArg(options::OPT_fgnu_runtime)) { - // FIXME: This is probably broken on 10.3? - if (isMacosxVersionLT(MacosxVersion, 10, 5)) - CmdArgs.push_back("-lgcc_s.10.4"); - else if (isMacosxVersionLT(MacosxVersion, 10, 6)) - CmdArgs.push_back("-lgcc_s.10.5"); - } else { - if (isMacosxVersionLT(MacosxVersion, 10, 3, 9)) - ; // Do nothing. - else if (isMacosxVersionLT(MacosxVersion, 10, 5)) - CmdArgs.push_back("-lgcc_s.10.4"); - else if (isMacosxVersionLT(MacosxVersion, 10, 6)) - CmdArgs.push_back("-lgcc_s.10.5"); - } - - if (isMacosxVersionLT(MacosxVersion, 10, 6)) { - CmdArgs.push_back("-lgcc"); - CmdArgs.push_back("-lSystem"); - } else { - CmdArgs.push_back("-lSystem"); - CmdArgs.push_back("-lgcc"); - } - } + // Let the tool chain choose which runtime library to link. + getDarwinToolChain().AddLinkRuntimeLibArgs(Args, CmdArgs); } if (!Args.hasArg(options::OPT_A) && @@ -1699,7 +2063,7 @@ void darwin::Link::ConstructJob(Compilation &C, const JobAction &JA, Args.AddAllArgs(CmdArgs, options::OPT_F); const char *Exec = - Args.MakeArgString(getToolChain().GetProgramPath(C, "ld").c_str()); + Args.MakeArgString(getToolChain().GetProgramPath(C, "ld")); Dest.addCommand(new Command(JA, Exec, CmdArgs)); // Find the first non-empty base input (we want to ignore linker @@ -1727,7 +2091,7 @@ void darwin::Link::ConstructJob(Compilation &C, const JobAction &JA, const char *Suffix = strrchr(BaseInput, '.'); if (Suffix && isSourceSuffix(Suffix + 1)) { const char *Exec = - Args.MakeArgString(getToolChain().GetProgramPath(C, "dsymutil").c_str()); + Args.MakeArgString(getToolChain().GetProgramPath(C, "dsymutil")); ArgStringList CmdArgs; CmdArgs.push_back(Output.getFilename()); C.getJobs().addCommand(new Command(JA, Exec, CmdArgs)); @@ -1755,7 +2119,135 @@ void darwin::Lipo::ConstructJob(Compilation &C, const JobAction &JA, CmdArgs.push_back(II.getFilename()); } const char *Exec = - Args.MakeArgString(getToolChain().GetProgramPath(C, "lipo").c_str()); + Args.MakeArgString(getToolChain().GetProgramPath(C, "lipo")); + Dest.addCommand(new Command(JA, Exec, CmdArgs)); +} + +void auroraux::Assemble::ConstructJob(Compilation &C, const JobAction &JA, + Job &Dest, const InputInfo &Output, + const InputInfoList &Inputs, + const ArgList &Args, + const char *LinkingOutput) const { + ArgStringList CmdArgs; + + Args.AddAllArgValues(CmdArgs, options::OPT_Wa_COMMA, + options::OPT_Xassembler); + + CmdArgs.push_back("-o"); + if (Output.isPipe()) + CmdArgs.push_back("-"); + else + CmdArgs.push_back(Output.getFilename()); + + for (InputInfoList::const_iterator + it = Inputs.begin(), ie = Inputs.end(); it != ie; ++it) { + const InputInfo &II = *it; + if (II.isPipe()) + CmdArgs.push_back("-"); + else + CmdArgs.push_back(II.getFilename()); + } + + const char *Exec = + Args.MakeArgString(getToolChain().GetProgramPath(C, "as")); + Dest.addCommand(new Command(JA, Exec, CmdArgs)); +} + +void auroraux::Link::ConstructJob(Compilation &C, const JobAction &JA, + Job &Dest, const InputInfo &Output, + const InputInfoList &Inputs, + const ArgList &Args, + const char *LinkingOutput) const { + const Driver &D = getToolChain().getHost().getDriver(); + ArgStringList CmdArgs; + + if ((!Args.hasArg(options::OPT_nostdlib)) && + (!Args.hasArg(options::OPT_shared))) { + CmdArgs.push_back("-e"); + CmdArgs.push_back("__start"); + } + + if (Args.hasArg(options::OPT_static)) { + CmdArgs.push_back("-Bstatic"); + } else { + CmdArgs.push_back("--eh-frame-hdr"); + CmdArgs.push_back("-Bdynamic"); + if (Args.hasArg(options::OPT_shared)) { + CmdArgs.push_back("-shared"); + } else { + CmdArgs.push_back("-dynamic-linker"); + CmdArgs.push_back("/lib/ld.so.1"); // 64Bit Path /lib/amd64/ld.so.1 + } + } + + if (Output.isPipe()) { + CmdArgs.push_back("-o"); + CmdArgs.push_back("-"); + } else if (Output.isFilename()) { + CmdArgs.push_back("-o"); + CmdArgs.push_back(Output.getFilename()); + } else { + assert(Output.isNothing() && "Invalid output."); + } + + if (!Args.hasArg(options::OPT_nostdlib) && + !Args.hasArg(options::OPT_nostartfiles)) { + if (!Args.hasArg(options::OPT_shared)) { + CmdArgs.push_back(Args.MakeArgString(getToolChain().GetFilePath(C, "crt0.o"))); + CmdArgs.push_back(Args.MakeArgString(getToolChain().GetFilePath(C, "crtbegin.o"))); + } else { + CmdArgs.push_back(Args.MakeArgString(getToolChain().GetFilePath(C, "crtbeginS.o"))); + } + } + + CmdArgs.push_back(MakeFormattedString(Args, + llvm::format("-L/opt/gcc4/lib/gcc/%s/4.2.4", + getToolChain().getTripleString().c_str()))); + + Args.AddAllArgs(CmdArgs, options::OPT_L); + Args.AddAllArgs(CmdArgs, options::OPT_T_Group); + Args.AddAllArgs(CmdArgs, options::OPT_e); + + for (InputInfoList::const_iterator + it = Inputs.begin(), ie = Inputs.end(); it != ie; ++it) { + const InputInfo &II = *it; + + // Don't try to pass LLVM inputs to a generic gcc. + if (II.getType() == types::TY_LLVMBC) + D.Diag(clang::diag::err_drv_no_linker_llvm_support) + << getToolChain().getTripleString(); + + if (II.isPipe()) + CmdArgs.push_back("-"); + else if (II.isFilename()) + CmdArgs.push_back(II.getFilename()); + else + II.getInputArg().renderAsInput(Args, CmdArgs); + } + + if (!Args.hasArg(options::OPT_nostdlib) && + !Args.hasArg(options::OPT_nodefaultlibs)) { + // FIXME: For some reason GCC passes -lgcc before adding + // the default system libraries. Just mimic this for now. + CmdArgs.push_back("-lgcc"); + + if (Args.hasArg(options::OPT_pthread)) + CmdArgs.push_back("-pthread"); + if (!Args.hasArg(options::OPT_shared)) + CmdArgs.push_back("-lc"); + CmdArgs.push_back("-lgcc"); + } + + if (!Args.hasArg(options::OPT_nostdlib) && + !Args.hasArg(options::OPT_nostartfiles)) { + if (!Args.hasArg(options::OPT_shared)) + CmdArgs.push_back(Args.MakeArgString(getToolChain().GetFilePath(C, "crtend.o"))); + else + CmdArgs.push_back(Args.MakeArgString(getToolChain().GetFilePath(C, "crtendS.o"))); + } + + const char *Exec = + Args.MakeArgString(getToolChain().GetProgramPath(C, "ld")); Dest.addCommand(new Command(JA, Exec, CmdArgs)); } @@ -1763,8 +2255,7 @@ void openbsd::Assemble::ConstructJob(Compilation &C, const JobAction &JA, Job &Dest, const InputInfo &Output, const InputInfoList &Inputs, const ArgList &Args, - const char *LinkingOutput) const -{ + const char *LinkingOutput) const { ArgStringList CmdArgs; Args.AddAllArgValues(CmdArgs, options::OPT_Wa_COMMA, @@ -1786,7 +2277,7 @@ void openbsd::Assemble::ConstructJob(Compilation &C, const JobAction &JA, } const char *Exec = - Args.MakeArgString(getToolChain().GetProgramPath(C, "as").c_str()); + Args.MakeArgString(getToolChain().GetProgramPath(C, "as")); Dest.addCommand(new Command(JA, Exec, CmdArgs)); } @@ -1798,12 +2289,19 @@ void openbsd::Link::ConstructJob(Compilation &C, const JobAction &JA, const Driver &D = getToolChain().getHost().getDriver(); ArgStringList CmdArgs; + if ((!Args.hasArg(options::OPT_nostdlib)) && + (!Args.hasArg(options::OPT_shared))) { + CmdArgs.push_back("-e"); + CmdArgs.push_back("__start"); + } + if (Args.hasArg(options::OPT_static)) { CmdArgs.push_back("-Bstatic"); } else { CmdArgs.push_back("--eh-frame-hdr"); + CmdArgs.push_back("-Bdynamic"); if (Args.hasArg(options::OPT_shared)) { - CmdArgs.push_back("-Bshareable"); + CmdArgs.push_back("-shared"); } else { CmdArgs.push_back("-dynamic-linker"); CmdArgs.push_back("/usr/libexec/ld.so"); @@ -1823,13 +2321,17 @@ void openbsd::Link::ConstructJob(Compilation &C, const JobAction &JA, if (!Args.hasArg(options::OPT_nostdlib) && !Args.hasArg(options::OPT_nostartfiles)) { if (!Args.hasArg(options::OPT_shared)) { - CmdArgs.push_back(Args.MakeArgString(getToolChain().GetFilePath(C, "crt0.o").c_str())); - CmdArgs.push_back(Args.MakeArgString(getToolChain().GetFilePath(C, "crtbegin.o").c_str())); + CmdArgs.push_back(Args.MakeArgString(getToolChain().GetFilePath(C, "crt0.o"))); + CmdArgs.push_back(Args.MakeArgString(getToolChain().GetFilePath(C, "crtbegin.o"))); } else { - CmdArgs.push_back(Args.MakeArgString(getToolChain().GetFilePath(C, "crtbeginS.o").c_str())); + CmdArgs.push_back(Args.MakeArgString(getToolChain().GetFilePath(C, "crtbeginS.o"))); } } + CmdArgs.push_back(MakeFormattedString(Args, + llvm::format("-L/usr/lib/gcc-lib/%s/3.3.5", + getToolChain().getTripleString().c_str()))); + Args.AddAllArgs(CmdArgs, options::OPT_L); Args.AddAllArgs(CmdArgs, options::OPT_T_Group); Args.AddAllArgs(CmdArgs, options::OPT_e); @@ -1841,7 +2343,7 @@ void openbsd::Link::ConstructJob(Compilation &C, const JobAction &JA, // Don't try to pass LLVM inputs to a generic gcc. if (II.getType() == types::TY_LLVMBC) D.Diag(clang::diag::err_drv_no_linker_llvm_support) - << getToolChain().getTripleString().c_str(); + << getToolChain().getTripleString(); if (II.isPipe()) CmdArgs.push_back("-"); @@ -1853,22 +2355,27 @@ void openbsd::Link::ConstructJob(Compilation &C, const JobAction &JA, if (!Args.hasArg(options::OPT_nostdlib) && !Args.hasArg(options::OPT_nodefaultlibs)) { + // FIXME: For some reason GCC passes -lgcc before adding + // the default system libraries. Just mimic this for now. + CmdArgs.push_back("-lgcc"); if (Args.hasArg(options::OPT_pthread)) CmdArgs.push_back("-pthread"); - CmdArgs.push_back("-lc"); + if (!Args.hasArg(options::OPT_shared)) + CmdArgs.push_back("-lc"); + CmdArgs.push_back("-lgcc"); } if (!Args.hasArg(options::OPT_nostdlib) && !Args.hasArg(options::OPT_nostartfiles)) { if (!Args.hasArg(options::OPT_shared)) - CmdArgs.push_back(Args.MakeArgString(getToolChain().GetFilePath(C, "crtend.o").c_str())); + CmdArgs.push_back(Args.MakeArgString(getToolChain().GetFilePath(C, "crtend.o"))); else - CmdArgs.push_back(Args.MakeArgString(getToolChain().GetFilePath(C, "crtendS.o").c_str())); + CmdArgs.push_back(Args.MakeArgString(getToolChain().GetFilePath(C, "crtendS.o"))); } const char *Exec = - Args.MakeArgString(getToolChain().GetProgramPath(C, "ld").c_str()); + Args.MakeArgString(getToolChain().GetProgramPath(C, "ld")); Dest.addCommand(new Command(JA, Exec, CmdArgs)); } @@ -1876,8 +2383,7 @@ void freebsd::Assemble::ConstructJob(Compilation &C, const JobAction &JA, Job &Dest, const InputInfo &Output, const InputInfoList &Inputs, const ArgList &Args, - const char *LinkingOutput) const -{ + const char *LinkingOutput) const { ArgStringList CmdArgs; // When building 32-bit code on FreeBSD/amd64, we have to explicitly @@ -1904,7 +2410,7 @@ void freebsd::Assemble::ConstructJob(Compilation &C, const JobAction &JA, } const char *Exec = - Args.MakeArgString(getToolChain().GetProgramPath(C, "as").c_str()); + Args.MakeArgString(getToolChain().GetProgramPath(C, "as")); Dest.addCommand(new Command(JA, Exec, CmdArgs)); } @@ -1948,12 +2454,12 @@ void freebsd::Link::ConstructJob(Compilation &C, const JobAction &JA, if (!Args.hasArg(options::OPT_nostdlib) && !Args.hasArg(options::OPT_nostartfiles)) { if (!Args.hasArg(options::OPT_shared)) { - CmdArgs.push_back(Args.MakeArgString(getToolChain().GetFilePath(C, "crt1.o").c_str())); - CmdArgs.push_back(Args.MakeArgString(getToolChain().GetFilePath(C, "crti.o").c_str())); - CmdArgs.push_back(Args.MakeArgString(getToolChain().GetFilePath(C, "crtbegin.o").c_str())); + CmdArgs.push_back(Args.MakeArgString(getToolChain().GetFilePath(C, "crt1.o"))); + CmdArgs.push_back(Args.MakeArgString(getToolChain().GetFilePath(C, "crti.o"))); + CmdArgs.push_back(Args.MakeArgString(getToolChain().GetFilePath(C, "crtbegin.o"))); } else { - CmdArgs.push_back(Args.MakeArgString(getToolChain().GetFilePath(C, "crti.o").c_str())); - CmdArgs.push_back(Args.MakeArgString(getToolChain().GetFilePath(C, "crtbeginS.o").c_str())); + CmdArgs.push_back(Args.MakeArgString(getToolChain().GetFilePath(C, "crti.o"))); + CmdArgs.push_back(Args.MakeArgString(getToolChain().GetFilePath(C, "crtbeginS.o"))); } } @@ -1968,7 +2474,7 @@ void freebsd::Link::ConstructJob(Compilation &C, const JobAction &JA, // Don't try to pass LLVM inputs to a generic gcc. if (II.getType() == types::TY_LLVMBC) D.Diag(clang::diag::err_drv_no_linker_llvm_support) - << getToolChain().getTripleString().c_str(); + << getToolChain().getTripleString(); if (II.isPipe()) CmdArgs.push_back("-"); @@ -2008,14 +2514,14 @@ void freebsd::Link::ConstructJob(Compilation &C, const JobAction &JA, if (!Args.hasArg(options::OPT_nostdlib) && !Args.hasArg(options::OPT_nostartfiles)) { if (!Args.hasArg(options::OPT_shared)) - CmdArgs.push_back(Args.MakeArgString(getToolChain().GetFilePath(C, "crtend.o").c_str())); + CmdArgs.push_back(Args.MakeArgString(getToolChain().GetFilePath(C, "crtend.o"))); else - CmdArgs.push_back(Args.MakeArgString(getToolChain().GetFilePath(C, "crtendS.o").c_str())); - CmdArgs.push_back(Args.MakeArgString(getToolChain().GetFilePath(C, "crtn.o").c_str())); + CmdArgs.push_back(Args.MakeArgString(getToolChain().GetFilePath(C, "crtendS.o"))); + CmdArgs.push_back(Args.MakeArgString(getToolChain().GetFilePath(C, "crtn.o"))); } const char *Exec = - Args.MakeArgString(getToolChain().GetProgramPath(C, "ld").c_str()); + Args.MakeArgString(getToolChain().GetProgramPath(C, "ld")); Dest.addCommand(new Command(JA, Exec, CmdArgs)); } @@ -2054,7 +2560,7 @@ void dragonfly::Assemble::ConstructJob(Compilation &C, const JobAction &JA, } const char *Exec = - Args.MakeArgString(getToolChain().GetProgramPath(C, "as").c_str()); + Args.MakeArgString(getToolChain().GetProgramPath(C, "as")); Dest.addCommand(new Command(JA, Exec, CmdArgs)); } @@ -2097,12 +2603,12 @@ void dragonfly::Link::ConstructJob(Compilation &C, const JobAction &JA, if (!Args.hasArg(options::OPT_nostdlib) && !Args.hasArg(options::OPT_nostartfiles)) { if (!Args.hasArg(options::OPT_shared)) { - CmdArgs.push_back(Args.MakeArgString(getToolChain().GetFilePath(C, "crt1.o").c_str())); - CmdArgs.push_back(Args.MakeArgString(getToolChain().GetFilePath(C, "crti.o").c_str())); - CmdArgs.push_back(Args.MakeArgString(getToolChain().GetFilePath(C, "crtbegin.o").c_str())); + CmdArgs.push_back(Args.MakeArgString(getToolChain().GetFilePath(C, "crt1.o"))); + CmdArgs.push_back(Args.MakeArgString(getToolChain().GetFilePath(C, "crti.o"))); + CmdArgs.push_back(Args.MakeArgString(getToolChain().GetFilePath(C, "crtbegin.o"))); } else { - CmdArgs.push_back(Args.MakeArgString(getToolChain().GetFilePath(C, "crti.o").c_str())); - CmdArgs.push_back(Args.MakeArgString(getToolChain().GetFilePath(C, "crtbeginS.o").c_str())); + CmdArgs.push_back(Args.MakeArgString(getToolChain().GetFilePath(C, "crti.o"))); + CmdArgs.push_back(Args.MakeArgString(getToolChain().GetFilePath(C, "crtbeginS.o"))); } } @@ -2117,7 +2623,7 @@ void dragonfly::Link::ConstructJob(Compilation &C, const JobAction &JA, // Don't try to pass LLVM inputs to a generic gcc. if (II.getType() == types::TY_LLVMBC) D.Diag(clang::diag::err_drv_no_linker_llvm_support) - << getToolChain().getTripleString().c_str(); + << getToolChain().getTripleString(); if (II.isPipe()) CmdArgs.push_back("-"); @@ -2171,13 +2677,13 @@ void dragonfly::Link::ConstructJob(Compilation &C, const JobAction &JA, if (!Args.hasArg(options::OPT_nostdlib) && !Args.hasArg(options::OPT_nostartfiles)) { if (!Args.hasArg(options::OPT_shared)) - CmdArgs.push_back(Args.MakeArgString(getToolChain().GetFilePath(C, "crtend.o").c_str())); + CmdArgs.push_back(Args.MakeArgString(getToolChain().GetFilePath(C, "crtend.o"))); else - CmdArgs.push_back(Args.MakeArgString(getToolChain().GetFilePath(C, "crtendS.o").c_str())); - CmdArgs.push_back(Args.MakeArgString(getToolChain().GetFilePath(C, "crtn.o").c_str())); + CmdArgs.push_back(Args.MakeArgString(getToolChain().GetFilePath(C, "crtendS.o"))); + CmdArgs.push_back(Args.MakeArgString(getToolChain().GetFilePath(C, "crtn.o"))); } const char *Exec = - Args.MakeArgString(getToolChain().GetProgramPath(C, "ld").c_str()); + Args.MakeArgString(getToolChain().GetProgramPath(C, "ld")); Dest.addCommand(new Command(JA, Exec, CmdArgs)); } diff --git a/lib/Driver/Tools.h b/lib/Driver/Tools.h index ab73496..6729da8 100644 --- a/lib/Driver/Tools.h +++ b/lib/Driver/Tools.h @@ -21,7 +21,7 @@ namespace driver { class Driver; namespace toolchains { - class Darwin_X86; + class Darwin; } namespace tools { @@ -33,6 +33,9 @@ namespace tools { const InputInfo &Output, const InputInfoList &Inputs) const; + void AddARMTargetArgs(const ArgList &Args, ArgStringList &CmdArgs) const; + void AddX86TargetArgs(const ArgList &Args, ArgStringList &CmdArgs) const; + public: Clang(const ToolChain &TC) : Tool("clang", TC) {} @@ -42,9 +45,9 @@ namespace tools { virtual void ConstructJob(Compilation &C, const JobAction &JA, Job &Dest, - const InputInfo &Output, - const InputInfoList &Inputs, - const ArgList &TCArgs, + const InputInfo &Output, + const InputInfoList &Inputs, + const ArgList &TCArgs, const char *LinkingOutput) const; }; @@ -56,9 +59,9 @@ namespace gcc { virtual void ConstructJob(Compilation &C, const JobAction &JA, Job &Dest, - const InputInfo &Output, - const InputInfoList &Inputs, - const ArgList &TCArgs, + const InputInfo &Output, + const InputInfoList &Inputs, + const ArgList &TCArgs, const char *LinkingOutput) const; /// RenderExtraToolArgs - Render any arguments necessary to force @@ -66,7 +69,7 @@ namespace gcc { virtual void RenderExtraToolArgs(ArgStringList &CmdArgs) const = 0; }; - + class VISIBILITY_HIDDEN Preprocess : public Common { public: Preprocess(const ToolChain &TC) : Common("gcc::Preprocess", TC) {} @@ -124,13 +127,26 @@ namespace gcc { } // end namespace gcc namespace darwin { - class VISIBILITY_HIDDEN CC1 : public Tool { + class VISIBILITY_HIDDEN DarwinTool : public Tool { + protected: + void AddDarwinArch(const ArgList &Args, ArgStringList &CmdArgs) const; + void AddDarwinSubArch(const ArgList &Args, ArgStringList &CmdArgs) const; + + const toolchains::Darwin &getDarwinToolChain() const { + return reinterpret_cast<const toolchains::Darwin&>(getToolChain()); + } + + public: + DarwinTool(const char *Name, const ToolChain &TC) : Tool(Name, TC) {}; + }; + + class VISIBILITY_HIDDEN CC1 : public DarwinTool { public: - static const char *getBaseInputName(const ArgList &Args, + static const char *getBaseInputName(const ArgList &Args, const InputInfoList &Input); - static const char *getBaseInputStem(const ArgList &Args, + static const char *getBaseInputStem(const ArgList &Args, const InputInfoList &Input); - static const char *getDependencyFileName(const ArgList &Args, + static const char *getDependencyFileName(const ArgList &Args, const InputInfoList &Inputs); protected: @@ -143,13 +159,13 @@ namespace darwin { void AddCPPOptionsArgs(const ArgList &Args, ArgStringList &CmdArgs, const InputInfoList &Inputs, const ArgStringList &OutputArgs) const; - void AddCPPUniqueOptionsArgs(const ArgList &Args, + void AddCPPUniqueOptionsArgs(const ArgList &Args, ArgStringList &CmdArgs, const InputInfoList &Inputs) const; void AddCPPArgs(const ArgList &Args, ArgStringList &CmdArgs) const; public: - CC1(const char *Name, const ToolChain &TC) : Tool(Name, TC) {} + CC1(const char *Name, const ToolChain &TC) : DarwinTool(Name, TC) {} virtual bool acceptsPipedInput() const { return true; } virtual bool canPipeOutput() const { return true; } @@ -162,9 +178,9 @@ namespace darwin { virtual void ConstructJob(Compilation &C, const JobAction &JA, Job &Dest, - const InputInfo &Output, - const InputInfoList &Inputs, - const ArgList &TCArgs, + const InputInfo &Output, + const InputInfoList &Inputs, + const ArgList &TCArgs, const char *LinkingOutput) const; }; @@ -174,15 +190,15 @@ namespace darwin { virtual void ConstructJob(Compilation &C, const JobAction &JA, Job &Dest, - const InputInfo &Output, - const InputInfoList &Inputs, - const ArgList &TCArgs, + const InputInfo &Output, + const InputInfoList &Inputs, + const ArgList &TCArgs, const char *LinkingOutput) const; }; - class VISIBILITY_HIDDEN Assemble : public Tool { + class VISIBILITY_HIDDEN Assemble : public DarwinTool { public: - Assemble(const ToolChain &TC) : Tool("darwin::Assemble", TC) {} + Assemble(const ToolChain &TC) : DarwinTool("darwin::Assemble", TC) {} virtual bool acceptsPipedInput() const { return true; } virtual bool canPipeOutput() const { return false; } @@ -190,27 +206,17 @@ namespace darwin { virtual void ConstructJob(Compilation &C, const JobAction &JA, Job &Dest, - const InputInfo &Output, - const InputInfoList &Inputs, - const ArgList &TCArgs, + const InputInfo &Output, + const InputInfoList &Inputs, + const ArgList &TCArgs, const char *LinkingOutput) const; }; - class VISIBILITY_HIDDEN Link : public Tool { - void AddDarwinArch(const ArgList &Args, ArgStringList &CmdArgs) const; - void AddDarwinSubArch(const ArgList &Args, ArgStringList &CmdArgs) const; + class VISIBILITY_HIDDEN Link : public DarwinTool { void AddLinkArgs(const ArgList &Args, ArgStringList &CmdArgs) const; - /// The default macosx-version-min. - const char *MacosxVersionMin; - - const toolchains::Darwin_X86 &getDarwinToolChain() const; - public: - Link(const ToolChain &TC, - const char *_MacosxVersionMin) - : Tool("darwin::Link", TC), MacosxVersionMin(_MacosxVersionMin) { - } + Link(const ToolChain &TC) : DarwinTool("darwin::Link", TC) {} virtual bool acceptsPipedInput() const { return false; } virtual bool canPipeOutput() const { return false; } @@ -218,15 +224,15 @@ namespace darwin { virtual void ConstructJob(Compilation &C, const JobAction &JA, Job &Dest, - const InputInfo &Output, - const InputInfoList &Inputs, - const ArgList &TCArgs, + const InputInfo &Output, + const InputInfoList &Inputs, + const ArgList &TCArgs, const char *LinkingOutput) const; }; - class VISIBILITY_HIDDEN Lipo : public Tool { + class VISIBILITY_HIDDEN Lipo : public DarwinTool { public: - Lipo(const ToolChain &TC) : Tool("darwin::Lipo", TC) {} + Lipo(const ToolChain &TC) : DarwinTool("darwin::Lipo", TC) {} virtual bool acceptsPipedInput() const { return false; } virtual bool canPipeOutput() const { return false; } @@ -234,9 +240,9 @@ namespace darwin { virtual void ConstructJob(Compilation &C, const JobAction &JA, Job &Dest, - const InputInfo &Output, - const InputInfoList &Inputs, - const ArgList &TCArgs, + const InputInfo &Output, + const InputInfoList &Inputs, + const ArgList &TCArgs, const char *LinkingOutput) const; }; } @@ -253,9 +259,9 @@ namespace openbsd { virtual void ConstructJob(Compilation &C, const JobAction &JA, Job &Dest, - const InputInfo &Output, - const InputInfoList &Inputs, - const ArgList &TCArgs, + const InputInfo &Output, + const InputInfoList &Inputs, + const ArgList &TCArgs, const char *LinkingOutput) const; }; class VISIBILITY_HIDDEN Link : public Tool { @@ -268,12 +274,12 @@ namespace openbsd { virtual void ConstructJob(Compilation &C, const JobAction &JA, Job &Dest, - const InputInfo &Output, - const InputInfoList &Inputs, - const ArgList &TCArgs, + const InputInfo &Output, + const InputInfoList &Inputs, + const ArgList &TCArgs, const char *LinkingOutput) const; }; -} +} // end namespace openbsd /// freebsd -- Directly call GNU Binutils assembler and linker namespace freebsd { @@ -287,9 +293,9 @@ namespace freebsd { virtual void ConstructJob(Compilation &C, const JobAction &JA, Job &Dest, - const InputInfo &Output, - const InputInfoList &Inputs, - const ArgList &TCArgs, + const InputInfo &Output, + const InputInfoList &Inputs, + const ArgList &TCArgs, const char *LinkingOutput) const; }; class VISIBILITY_HIDDEN Link : public Tool { @@ -302,12 +308,46 @@ namespace freebsd { virtual void ConstructJob(Compilation &C, const JobAction &JA, Job &Dest, - const InputInfo &Output, - const InputInfoList &Inputs, - const ArgList &TCArgs, + const InputInfo &Output, + const InputInfoList &Inputs, + const ArgList &TCArgs, const char *LinkingOutput) const; }; -} +} // end namespace freebsd + + /// auroraux -- Directly call GNU Binutils assembler and linker +namespace auroraux { + class VISIBILITY_HIDDEN Assemble : public Tool { + public: + Assemble(const ToolChain &TC) : Tool("auroraux::Assemble", TC) {} + + virtual bool acceptsPipedInput() const { return true; } + virtual bool canPipeOutput() const { return true; } + virtual bool hasIntegratedCPP() const { return false; } + + virtual void ConstructJob(Compilation &C, const JobAction &JA, + Job &Dest, + const InputInfo &Output, + const InputInfoList &Inputs, + const ArgList &TCArgs, + const char *LinkingOutput) const; + }; + class VISIBILITY_HIDDEN Link : public Tool { + public: + Link(const ToolChain &TC) : Tool("auroraux::Link", TC) {} + + virtual bool acceptsPipedInput() const { return true; } + virtual bool canPipeOutput() const { return true; } + virtual bool hasIntegratedCPP() const { return false; } + + virtual void ConstructJob(Compilation &C, const JobAction &JA, + Job &Dest, + const InputInfo &Output, + const InputInfoList &Inputs, + const ArgList &TCArgs, + const char *LinkingOutput) const; + }; +} // end namespace auroraux /// dragonfly -- Directly call GNU Binutils assembler and linker namespace dragonfly { @@ -321,9 +361,9 @@ namespace dragonfly { virtual void ConstructJob(Compilation &C, const JobAction &JA, Job &Dest, - const InputInfo &Output, - const InputInfoList &Inputs, - const ArgList &TCArgs, + const InputInfo &Output, + const InputInfoList &Inputs, + const ArgList &TCArgs, const char *LinkingOutput) const; }; class VISIBILITY_HIDDEN Link : public Tool { @@ -336,15 +376,15 @@ namespace dragonfly { virtual void ConstructJob(Compilation &C, const JobAction &JA, Job &Dest, - const InputInfo &Output, - const InputInfoList &Inputs, - const ArgList &TCArgs, + const InputInfo &Output, + const InputInfoList &Inputs, + const ArgList &TCArgs, const char *LinkingOutput) const; }; -} +} // end namespace dragonfly } // end namespace toolchains } // end namespace driver } // end namespace clang -#endif +#endif // CLANG_LIB_DRIVER_TOOLS_H_ diff --git a/lib/Driver/Types.cpp b/lib/Driver/Types.cpp index e89e973..eee8c19 100644 --- a/lib/Driver/Types.cpp +++ b/lib/Driver/Types.cpp @@ -35,38 +35,38 @@ static Info &getInfo(unsigned id) { return TypeInfos[id - 1]; } -const char *types::getTypeName(ID Id) { - return getInfo(Id).Name; +const char *types::getTypeName(ID Id) { + return getInfo(Id).Name; } -types::ID types::getPreprocessedType(ID Id) { - return getInfo(Id).PreprocessedType; +types::ID types::getPreprocessedType(ID Id) { + return getInfo(Id).PreprocessedType; } -const char *types::getTypeTempSuffix(ID Id) { - return getInfo(Id).TempSuffix; +const char *types::getTypeTempSuffix(ID Id) { + return getInfo(Id).TempSuffix; } -bool types::onlyAssembleType(ID Id) { - return strchr(getInfo(Id).Flags, 'a'); +bool types::onlyAssembleType(ID Id) { + return strchr(getInfo(Id).Flags, 'a'); } -bool types::onlyPrecompileType(ID Id) { - return strchr(getInfo(Id).Flags, 'p'); +bool types::onlyPrecompileType(ID Id) { + return strchr(getInfo(Id).Flags, 'p'); } -bool types::canTypeBeUserSpecified(ID Id) { - return strchr(getInfo(Id).Flags, 'u'); +bool types::canTypeBeUserSpecified(ID Id) { + return strchr(getInfo(Id).Flags, 'u'); } -bool types::appendSuffixForType(ID Id) { - return strchr(getInfo(Id).Flags, 'A'); +bool types::appendSuffixForType(ID Id) { + return strchr(getInfo(Id).Flags, 'A'); } -bool types::canLipoType(ID Id) { +bool types::canLipoType(ID Id) { return (Id == TY_Nothing || Id == TY_Image || - Id == TY_Object); + Id == TY_Object); } bool types::isAcceptedByClang(ID Id) { @@ -83,6 +83,7 @@ bool types::isAcceptedByClang(ID Id) { case TY_ObjCHeader: case TY_PP_ObjCHeader: case TY_CXXHeader: case TY_PP_CXXHeader: case TY_ObjCXXHeader: case TY_PP_ObjCXXHeader: + case TY_AST: return true; } } @@ -128,6 +129,7 @@ types::ID types::lookupTypeForExtension(const char *Ext) { case 3: if (memcmp(Ext, "ads", 3) == 0) return TY_Ada; if (memcmp(Ext, "adb", 3) == 0) return TY_Ada; + if (memcmp(Ext, "ast", 3) == 0) return TY_AST; if (memcmp(Ext, "cxx", 3) == 0) return TY_CXX; if (memcmp(Ext, "cpp", 3) == 0) return TY_CXX; if (memcmp(Ext, "CPP", 3) == 0) return TY_CXX; @@ -152,7 +154,7 @@ types::ID types::lookupTypeForTypeSpecifier(const char *Name) { for (unsigned i=0; i<numTypes; ++i) { types::ID Id = (types::ID) (i + 1); - if (canTypeBeUserSpecified(Id) && + if (canTypeBeUserSpecified(Id) && memcmp(Name, getInfo(Id).Name, N + 1) == 0) return Id; } @@ -162,25 +164,25 @@ types::ID types::lookupTypeForTypeSpecifier(const char *Name) { // FIXME: Why don't we just put this list in the defs file, eh. -unsigned types::getNumCompilationPhases(ID Id) { +unsigned types::getNumCompilationPhases(ID Id) { if (Id == TY_Object) return 1; - + unsigned N = 0; if (getPreprocessedType(Id) != TY_INVALID) N += 1; - + if (onlyAssembleType(Id)) return N + 2; // assemble, link if (onlyPrecompileType(Id)) return N + 1; // precompile - + return N + 3; // compile, assemble, link } phases::ID types::getCompilationPhase(ID Id, unsigned N) { assert(N < getNumCompilationPhases(Id) && "Invalid index."); - + if (Id == TY_Object) return phases::Link; @@ -200,6 +202,6 @@ phases::ID types::getCompilationPhase(ID Id, unsigned N) { return phases::Compile; if (N == 1) return phases::Assemble; - + return phases::Link; } |