diff options
Diffstat (limited to 'lib/Driver/ToolChains.cpp')
| -rw-r--r-- | lib/Driver/ToolChains.cpp | 516 | 
1 files changed, 469 insertions, 47 deletions
diff --git a/lib/Driver/ToolChains.cpp b/lib/Driver/ToolChains.cpp index 471c47dd2b50..13b8b4609ec0 100644 --- a/lib/Driver/ToolChains.cpp +++ b/lib/Driver/ToolChains.cpp @@ -1,4 +1,4 @@ -//===--- ToolChains.cpp - ToolChain Implementations ---------------------*-===// +//===--- ToolChains.cpp - ToolChain Implementations -----------------------===//  //  //                     The LLVM Compiler Infrastructure  // @@ -23,8 +23,11 @@  #include "llvm/ADT/SmallString.h"  #include "llvm/ADT/StringExtras.h"  #include "llvm/Support/ErrorHandling.h" +#include "llvm/Support/FileSystem.h" +#include "llvm/Support/MemoryBuffer.h"  #include "llvm/Support/raw_ostream.h" -#include "llvm/System/Path.h" +#include "llvm/Support/Path.h" +#include "llvm/Support/system_error.h"  #include <cstdlib> // ::getenv @@ -59,6 +62,10 @@ types::ID Darwin::LookupTypeForExtension(const char *Ext) const {    return Ty;  } +bool Darwin::HasNativeLLVMSupport() const { +  return true; +} +  // FIXME: Can we tablegen this?  static const char *GetArmArchForMArch(llvm::StringRef Value) {    if (Value == "armv6k") @@ -142,7 +149,8 @@ DarwinGCC::DarwinGCC(const HostInfo &Host, const llvm::Triple& Triple)    // Try the next major version if that tool chain dir is invalid.    std::string Tmp = "/usr/lib/gcc/" + ToolChainDir; -  if (!llvm::sys::Path(Tmp).exists()) { +  bool Exists; +  if (llvm::sys::fs::exists(Tmp, Exists) || Exists) {      std::string Next = "i686-apple-darwin";      Next += llvm::utostr(DarwinVersion[0] + 1);      Next += "/"; @@ -156,7 +164,7 @@ DarwinGCC::DarwinGCC(const HostInfo &Host, const llvm::Triple& Triple)      //      // FIXME: Drop dependency on gcc's tool chain.      Tmp = "/usr/lib/gcc/" + Next; -    if (llvm::sys::Path(Tmp).exists()) +    if (!llvm::sys::fs::exists(Tmp, Exists) && Exists)        ToolChainDir = Next;    } @@ -301,19 +309,20 @@ void DarwinGCC::AddLinkSearchPathArgs(const ArgList &Args,    CmdArgs.push_back(Args.MakeArgString("-L/usr/lib/" + ToolChainDir));    Tmp = getDriver().Dir + "/../lib/gcc/" + ToolChainDir; -  if (llvm::sys::Path(Tmp).exists()) +  bool Exists; +  if (!llvm::sys::fs::exists(Tmp, Exists) && Exists)      CmdArgs.push_back(Args.MakeArgString("-L" + Tmp));    Tmp = getDriver().Dir + "/../lib/gcc"; -  if (llvm::sys::Path(Tmp).exists()) +  if (!llvm::sys::fs::exists(Tmp, Exists) && Exists)      CmdArgs.push_back(Args.MakeArgString("-L" + Tmp));    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));    Tmp = getDriver().Dir + "/../lib/" + ToolChainDir; -  if (llvm::sys::Path(Tmp).exists()) +  if (!llvm::sys::fs::exists(Tmp, Exists) && Exists)      CmdArgs.push_back(Args.MakeArgString("-L" + Tmp));    Tmp = getDriver().Dir + "/../lib"; -  if (llvm::sys::Path(Tmp).exists()) +  if (!llvm::sys::fs::exists(Tmp, Exists) && Exists)      CmdArgs.push_back(Args.MakeArgString("-L" + Tmp));    CmdArgs.push_back(Args.MakeArgString("-L/usr/lib/gcc/" + ToolChainDir +                                         "/../../../" + ToolChainDir)); @@ -369,10 +378,30 @@ void DarwinGCC::AddLinkRuntimeLibArgs(const ArgList &Args,  DarwinClang::DarwinClang(const HostInfo &Host, const llvm::Triple& Triple)    : Darwin(Host, Triple)  { +  getProgramPaths().push_back(getDriver().getInstalledDir()); +  if (getDriver().getInstalledDir() != getDriver().Dir) +    getProgramPaths().push_back(getDriver().Dir); +    // We expect 'as', 'ld', etc. to be adjacent to our install dir.    getProgramPaths().push_back(getDriver().getInstalledDir());    if (getDriver().getInstalledDir() != getDriver().Dir)      getProgramPaths().push_back(getDriver().Dir); + +  // For fallback, we need to know how to find the GCC cc1 executables, so we +  // also add the GCC libexec paths. This is legiy code that can be removed once +  // fallback is no longer useful. +  std::string ToolChainDir = "i686-apple-darwin"; +  ToolChainDir += llvm::utostr(DarwinVersion[0]); +  ToolChainDir += "/4.2.1"; + +  std::string Path = getDriver().Dir; +  Path += "/../libexec/gcc/"; +  Path += ToolChainDir; +  getProgramPaths().push_back(Path); + +  Path = "/usr/libexec/gcc/"; +  Path += ToolChainDir; +  getProgramPaths().push_back(Path);  }  void DarwinClang::AddLinkSearchPathArgs(const ArgList &Args, @@ -431,12 +460,14 @@ void DarwinClang::AddLinkSearchPathArgs(const ArgList &Args,    if (ArchSpecificDir) {      P.appendComponent(ArchSpecificDir); -    if (P.exists()) +    bool Exists; +    if (!llvm::sys::fs::exists(P.str(), Exists) && Exists)        CmdArgs.push_back(Args.MakeArgString("-L" + P.str()));      P.eraseComponent();    } -  if (P.exists()) +  bool Exists; +  if (!llvm::sys::fs::exists(P.str(), Exists) && Exists)      CmdArgs.push_back(Args.MakeArgString("-L" + P.str()));  } @@ -477,11 +508,20 @@ void DarwinClang::AddLinkRuntimeLibArgs(const ArgList &Args,      else if (isMacosxVersionLT(10, 6))        CmdArgs.push_back("-lgcc_s.10.5"); -    // For OS X, we only need a static runtime library when targetting 10.4, to -    // provide versions of the static functions which were omitted from -    // 10.4.dylib. -    if (isMacosxVersionLT(10, 5)) +    // For OS X, we thought we would only need a static runtime library when +    // targetting 10.4, to provide versions of the static functions which were +    // omitted from 10.4.dylib. +    // +    // Unfortunately, that turned out to not be true, because Darwin system +    // headers can still use eprintf on i386, and it is not exported from +    // libSystem. Therefore, we still must provide a runtime library just for +    // the tiny tiny handful of projects that *might* use that symbol. +    if (isMacosxVersionLT(10, 5)) {        DarwinStaticLib = "libclang_rt.10.4.a"; +    } else { +      if (getTriple().getArch() == llvm::Triple::x86) +        DarwinStaticLib = "libclang_rt.eprintf.a"; +    }    }    /// Add the target specific static library, if needed. @@ -493,10 +533,8 @@ void DarwinClang::AddLinkRuntimeLibArgs(const ArgList &Args,      // For now, allow missing resource libraries to support developers who may      // not have compiler-rt checked out or integrated into their build. -    if (!P.exists()) -      getDriver().Diag(clang::diag::warn_drv_missing_resource_library) -        << P.str(); -    else +    bool Exists; +    if (!llvm::sys::fs::exists(P.str(), Exists) && Exists)        CmdArgs.push_back(Args.MakeArgString(P.str()));    }  } @@ -574,6 +612,72 @@ void Darwin::AddDeploymentTarget(DerivedArgList &Args) const {    setTarget(iPhoneVersion, Major, Minor, Micro);  } +void DarwinClang::AddCXXStdlibLibArgs(const ArgList &Args, +                                      ArgStringList &CmdArgs) const { +  CXXStdlibType Type = GetCXXStdlibType(Args); + +  switch (Type) { +  case ToolChain::CST_Libcxx: +    CmdArgs.push_back("-lc++"); +    break; + +  case ToolChain::CST_Libstdcxx: { +    // Unfortunately, -lstdc++ doesn't always exist in the standard search path; +    // it was previously found in the gcc lib dir. However, for all the Darwin +    // platforms we care about it was -lstdc++.6, so we search for that +    // explicitly if we can't see an obvious -lstdc++ candidate. + +    // Check in the sysroot first. +    bool Exists; +    if (const Arg *A = Args.getLastArg(options::OPT_isysroot)) { +      llvm::sys::Path P(A->getValue(Args)); +      P.appendComponent("usr"); +      P.appendComponent("lib"); +      P.appendComponent("libstdc++.dylib"); + +      if (llvm::sys::fs::exists(P.str(), Exists) || !Exists) { +        P.eraseComponent(); +        P.appendComponent("libstdc++.6.dylib"); +        if (!llvm::sys::fs::exists(P.str(), Exists) && Exists) { +          CmdArgs.push_back(Args.MakeArgString(P.str())); +          return; +        } +      } +    } + +    // Otherwise, look in the root. +    if ((llvm::sys::fs::exists("/usr/lib/libstdc++.dylib", Exists) || !Exists)&& +      (!llvm::sys::fs::exists("/usr/lib/libstdc++.6.dylib", Exists) && Exists)){ +      CmdArgs.push_back("/usr/lib/libstdc++.6.dylib"); +      return; +    } + +    // Otherwise, let the linker search. +    CmdArgs.push_back("-lstdc++"); +    break; +  } +  } +} + +void DarwinClang::AddCCKextLibArgs(const ArgList &Args, +                                   ArgStringList &CmdArgs) const { + +  // For Darwin platforms, use the compiler-rt-based support library +  // instead of the gcc-provided one (which is also incidentally +  // only present in the gcc lib dir, which makes it hard to find). + +  llvm::sys::Path P(getDriver().ResourceDir); +  P.appendComponent("lib"); +  P.appendComponent("darwin"); +  P.appendComponent("libclang_rt.cc_kext.a"); +   +  // For now, allow missing resource libraries to support developers who may +  // not have compiler-rt checked out or integrated into their build. +  bool Exists; +  if (!llvm::sys::fs::exists(P.str(), Exists) && Exists) +    CmdArgs.push_back(Args.MakeArgString(P.str())); +} +  DerivedArgList *Darwin::TranslateArgs(const DerivedArgList &Args,                                        const char *BoundArch) const {    DerivedArgList *DAL = new DerivedArgList(Args.getBaseArgs()); @@ -595,6 +699,7 @@ DerivedArgList *Darwin::TranslateArgs(const DerivedArgList &Args,        if (getArchName() != A->getValue(Args, 0))          continue; +      Arg *OriginalArg = A;        unsigned Index = Args.getBaseArgs().MakeIndex(A->getValue(Args, 1));        unsigned Prev = Index;        Arg *XarchArg = Opts.ParseOneArg(Args, Index); @@ -618,6 +723,20 @@ DerivedArgList *Darwin::TranslateArgs(const DerivedArgList &Args,        A = XarchArg;        DAL->AddSynthesizedArg(A); + +      // Linker input arguments require custom handling. The problem is that we +      // have already constructed the phase actions, so we can not treat them as +      // "input arguments". +      if (A->getOption().isLinkerInput()) { +        // Convert the argument into individual Zlinker_input_args. +        for (unsigned i = 0, e = A->getNumValues(); i != e; ++i) { +          DAL->AddSeparateArg(OriginalArg, +                              Opts.getOption(options::OPT_Zlinker_input), +                              A->getValue(Args, i)); +           +        } +        continue; +      }      }      // Sob. These is strictly gcc compatible for the time being. Apple @@ -937,7 +1056,7 @@ Tool &TCEToolChain::SelectTool(const Compilation &C,  /// OpenBSD - OpenBSD tool chain which can call as(1) and ld(1) directly.  OpenBSD::OpenBSD(const HostInfo &Host, const llvm::Triple& Triple) -  : Generic_GCC(Host, Triple) { +  : Generic_ELF(Host, Triple) {    getFilePaths().push_back(getDriver().Dir + "/../lib");    getFilePaths().push_back("/usr/lib");  } @@ -949,11 +1068,20 @@ Tool &OpenBSD::SelectTool(const Compilation &C, const JobAction &JA) const {    else      Key = JA.getKind(); +  bool UseIntegratedAs = C.getArgs().hasFlag(options::OPT_integrated_as, +                                             options::OPT_no_integrated_as, +                                             IsIntegratedAssemblerDefault()); +    Tool *&T = Tools[Key];    if (!T) {      switch (Key) { -    case Action::AssembleJobClass: -      T = new tools::openbsd::Assemble(*this); break; +    case Action::AssembleJobClass: { +      if (UseIntegratedAs) +        T = new tools::ClangAs(*this); +      else +        T = new tools::openbsd::Assemble(*this); +      break; +    }      case Action::LinkJobClass:        T = new tools::openbsd::Link(*this); break;      default: @@ -967,7 +1095,7 @@ Tool &OpenBSD::SelectTool(const Compilation &C, const JobAction &JA) const {  /// FreeBSD - FreeBSD tool chain which can call as(1) and ld(1) directly.  FreeBSD::FreeBSD(const HostInfo &Host, const llvm::Triple& Triple) -  : Generic_GCC(Host, Triple) { +  : Generic_ELF(Host, Triple) {    // Determine if we are compiling 32-bit code on an x86_64 platform.    bool Lib32 = false; @@ -994,11 +1122,19 @@ Tool &FreeBSD::SelectTool(const Compilation &C, const JobAction &JA) const {    else      Key = JA.getKind(); +  bool UseIntegratedAs = C.getArgs().hasFlag(options::OPT_integrated_as, +                                             options::OPT_no_integrated_as, +                                             IsIntegratedAssemblerDefault()); +    Tool *&T = Tools[Key];    if (!T) {      switch (Key) {      case Action::AssembleJobClass: -      T = new tools::freebsd::Assemble(*this); break; +      if (UseIntegratedAs) +        T = new tools::ClangAs(*this); +      else +        T = new tools::freebsd::Assemble(*this); +      break;      case Action::LinkJobClass:        T = new tools::freebsd::Link(*this); break;      default: @@ -1009,6 +1145,57 @@ Tool &FreeBSD::SelectTool(const Compilation &C, const JobAction &JA) const {    return *T;  } +/// NetBSD - NetBSD tool chain which can call as(1) and ld(1) directly. + +NetBSD::NetBSD(const HostInfo &Host, const llvm::Triple& Triple) +  : Generic_ELF(Host, Triple) { + +  // Determine if we are compiling 32-bit code on an x86_64 platform. +  bool Lib32 = false; +  if (Triple.getArch() == llvm::Triple::x86 && +      llvm::Triple(getDriver().DefaultHostTriple).getArch() == +        llvm::Triple::x86_64) +    Lib32 = true; + +  getProgramPaths().push_back(getDriver().Dir + "/../libexec"); +  getProgramPaths().push_back("/usr/libexec"); +  if (Lib32) { +    getFilePaths().push_back("/usr/lib/i386"); +  } else { +    getFilePaths().push_back("/usr/lib"); +  } +} + +Tool &NetBSD::SelectTool(const Compilation &C, const JobAction &JA) const { +  Action::ActionClass Key; +  if (getDriver().ShouldUseClangCompiler(C, JA, getTriple())) +    Key = Action::AnalyzeJobClass; +  else +    Key = JA.getKind(); + +  bool UseIntegratedAs = C.getArgs().hasFlag(options::OPT_integrated_as, +                                             options::OPT_no_integrated_as, +                                             IsIntegratedAssemblerDefault()); + +  Tool *&T = Tools[Key]; +  if (!T) { +    switch (Key) { +    case Action::AssembleJobClass: +      if (UseIntegratedAs) +        T = new tools::ClangAs(*this); +      else +        T = new tools::netbsd::Assemble(*this); +      break; +    case Action::LinkJobClass: +      T = new tools::netbsd::Link(*this); break; +    default: +      T = &Generic_GCC::SelectTool(C, JA); +    } +  } + +  return *T; +} +  /// Minix - Minix tool chain which can call as(1) and ld(1) directly.  Minix::Minix(const HostInfo &Host, const llvm::Triple& Triple) @@ -1083,28 +1270,253 @@ Tool &AuroraUX::SelectTool(const Compilation &C, const JobAction &JA) const {  /// Linux toolchain (very bare-bones at the moment). -Linux::Linux(const HostInfo &Host, const llvm::Triple& Triple) -  : Generic_GCC(Host, Triple) { -  getFilePaths().push_back(getDriver().Dir + -                           "/../lib/clang/" CLANG_VERSION_STRING "/"); -  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 -  // libraries. If we had our own crtbegin.o/crtend.o/etc, we could probably -  // get away with using shared versions in /usr/lib, though. -  // We could fall back to the approach we used for includes (a massive -  // list), but that's messy at best. +enum LinuxDistro { +  DebianLenny, +  DebianSqueeze, +  Exherbo, +  Fedora13, +  Fedora14, +  OpenSuse11_3, +  UbuntuJaunty, +  UbuntuKarmic, +  UbuntuLucid, +  UbuntuMaverick, +  UnknownDistro +}; + +static bool IsFedora(enum LinuxDistro Distro) { +  return Distro == Fedora13 || Distro == Fedora14; +} + +static bool IsOpenSuse(enum LinuxDistro Distro) { +  return Distro == OpenSuse11_3; +} + +static bool IsDebian(enum LinuxDistro Distro) { +  return Distro == DebianLenny || Distro == DebianSqueeze; +} + +static bool IsUbuntu(enum LinuxDistro Distro) { +  return Distro == UbuntuLucid || Distro == UbuntuMaverick ||  +         Distro == UbuntuJaunty || Distro == UbuntuKarmic; +} + +static bool IsDebianBased(enum LinuxDistro Distro) { +  return IsDebian(Distro) || IsUbuntu(Distro); +} + +static bool HasMultilib(llvm::Triple::ArchType Arch, enum LinuxDistro Distro) { +  if (Arch == llvm::Triple::x86_64) { +    bool Exists; +    if (Distro == Exherbo && +        (llvm::sys::fs::exists("/usr/lib32/libc.so", Exists) || !Exists)) +      return false; + +    return true; +  } +  if (Arch == llvm::Triple::x86 && IsDebianBased(Distro)) +    return true; +  return false; +} + +static LinuxDistro DetectLinuxDistro(llvm::Triple::ArchType Arch) { +  llvm::OwningPtr<llvm::MemoryBuffer> File; +  if (!llvm::MemoryBuffer::getFile("/etc/lsb-release", File)) { +    llvm::StringRef Data = File.get()->getBuffer(); +    llvm::SmallVector<llvm::StringRef, 8> Lines; +    Data.split(Lines, "\n"); +    for (unsigned int i = 0, s = Lines.size(); i < s; ++ i) { +      if (Lines[i] == "DISTRIB_CODENAME=maverick") +        return UbuntuMaverick; +      else if (Lines[i] == "DISTRIB_CODENAME=lucid") +        return UbuntuLucid; +      else if (Lines[i] == "DISTRIB_CODENAME=jaunty") +        return UbuntuJaunty; +      else if (Lines[i] == "DISTRIB_CODENAME=karmic") +        return UbuntuKarmic; +    } +    return UnknownDistro; +  } + +  if (!llvm::MemoryBuffer::getFile("/etc/redhat-release", File)) { +    llvm::StringRef Data = File.get()->getBuffer(); +    if (Data.startswith("Fedora release 14 (Laughlin)")) +      return Fedora14; +    else if (Data.startswith("Fedora release 13 (Goddard)")) +      return Fedora13; +    return UnknownDistro; +  } + +  if (!llvm::MemoryBuffer::getFile("/etc/debian_version", File)) { +    llvm::StringRef Data = File.get()->getBuffer(); +    if (Data[0] == '5') +      return DebianLenny; +    else if (Data.startswith("squeeze/sid")) +      return DebianSqueeze; +    return UnknownDistro; +  } + +  if (!llvm::MemoryBuffer::getFile("/etc/SuSE-release", File)) { +    llvm::StringRef Data = File.get()->getBuffer(); +    if (Data.startswith("openSUSE 11.3")) +      return OpenSuse11_3; +    return UnknownDistro; +  } + +  bool Exists; +  if (!llvm::sys::fs::exists("/etc/exherbo-release", Exists) && Exists) +    return Exherbo; + +  return UnknownDistro; +} + +Linux::Linux(const HostInfo &Host, const llvm::Triple &Triple) +  : Generic_ELF(Host, Triple) { +  llvm::Triple::ArchType Arch = +    llvm::Triple(getDriver().DefaultHostTriple).getArch(); + +  std::string Suffix32  = ""; +  if (Arch == llvm::Triple::x86_64) +    Suffix32 = "/32"; + +  std::string Suffix64  = ""; +  if (Arch == llvm::Triple::x86) +    Suffix64 = "/64"; + +  std::string Lib32 = "lib"; + +  bool Exists; +  if (!llvm::sys::fs::exists("/lib32", Exists) && Exists) +    Lib32 = "lib32"; + +  std::string Lib64 = "lib"; +  bool Symlink; +  if (!llvm::sys::fs::exists("/lib64", Exists) && Exists && +      (llvm::sys::fs::is_symlink("/lib64", Symlink) || !Symlink)) +    Lib64 = "lib64"; + +  std::string GccTriple = ""; +  if (Arch == llvm::Triple::arm) { +    if (!llvm::sys::fs::exists("/usr/lib/gcc/arm-linux-gnueabi", Exists) && +        Exists) +      GccTriple = "arm-linux-gnueabi"; +  } else if (Arch == llvm::Triple::x86_64) { +    if (!llvm::sys::fs::exists("/usr/lib/gcc/x86_64-linux-gnu", Exists) && +        Exists) +      GccTriple = "x86_64-linux-gnu"; +    else if (!llvm::sys::fs::exists("/usr/lib/gcc/x86_64-unknown-linux-gnu", +             Exists) && Exists) +      GccTriple = "x86_64-unknown-linux-gnu"; +    else if (!llvm::sys::fs::exists("/usr/lib/gcc/x86_64-pc-linux-gnu", +             Exists) && Exists) +      GccTriple = "x86_64-pc-linux-gnu"; +    else if (!llvm::sys::fs::exists("/usr/lib/gcc/x86_64-redhat-linux", +             Exists) && Exists) +      GccTriple = "x86_64-redhat-linux"; +    else if (!llvm::sys::fs::exists("/usr/lib64/gcc/x86_64-suse-linux", +             Exists) && Exists) +      GccTriple = "x86_64-suse-linux"; +    else if (!llvm::sys::fs::exists("/usr/lib/gcc/x86_64-manbo-linux-gnu", +             Exists) && Exists) +      GccTriple = "x86_64-manbo-linux-gnu"; +  } else if (Arch == llvm::Triple::x86) { +    if (!llvm::sys::fs::exists("/usr/lib/gcc/i686-linux-gnu", Exists) && Exists) +      GccTriple = "i686-linux-gnu"; +    else if (!llvm::sys::fs::exists("/usr/lib/gcc/i686-pc-linux-gnu", Exists) && +             Exists) +      GccTriple = "i686-pc-linux-gnu"; +    else if (!llvm::sys::fs::exists("/usr/lib/gcc/i486-linux-gnu", Exists) && +             Exists) +      GccTriple = "i486-linux-gnu"; +    else if (!llvm::sys::fs::exists("/usr/lib/gcc/i686-redhat-linux", Exists) && +             Exists) +      GccTriple = "i686-redhat-linux"; +    else if (!llvm::sys::fs::exists("/usr/lib/gcc/i586-suse-linux", Exists) && +             Exists) +      GccTriple = "i586-suse-linux"; +  } + +  const char* GccVersions[] = {"4.5.1", "4.5", "4.4.5", "4.4.4", "4.4.3", "4.4", +                               "4.3.4", "4.3.3", "4.3.2"}; +  std::string Base = ""; +  for (unsigned i = 0; i < sizeof(GccVersions)/sizeof(char*); ++i) { +    std::string Suffix = GccTriple + "/" + GccVersions[i]; +    std::string t1 = "/usr/lib/gcc/" + Suffix; +    if (!llvm::sys::fs::exists(t1 + "/crtbegin.o", Exists) && Exists) { +      Base = t1; +      break; +    } +    std::string t2 = "/usr/lib64/gcc/" + Suffix; +    if (!llvm::sys::fs::exists(t2 + "/crtbegin.o", Exists) && Exists) { +      Base = t2; +      break; +    } +  } + +  path_list &Paths = getFilePaths(); +  bool Is32Bits = getArch() == llvm::Triple::x86; + +  std::string Suffix; +  std::string Lib; + +  if (Is32Bits) { +    Suffix = Suffix32; +    Lib = Lib32; +  } else { +    Suffix = Suffix64; +    Lib = Lib64; +  } + +  llvm::sys::Path LinkerPath(Base + "/../../../../" + GccTriple + "/bin/ld"); +  if (!llvm::sys::fs::exists(LinkerPath.str(), Exists) && Exists) +    Linker = LinkerPath.str(); +  else +    Linker = GetProgramPath("ld"); + +  LinuxDistro Distro = DetectLinuxDistro(Arch); + +  if (IsUbuntu(Distro)) { +    ExtraOpts.push_back("-z"); +    ExtraOpts.push_back("relro"); +  } + +  if (Arch == llvm::Triple::arm) +    ExtraOpts.push_back("-X"); + +  if (IsFedora(Distro) || Distro == UbuntuMaverick) +    ExtraOpts.push_back("--hash-style=gnu"); + +  if (IsDebian(Distro) || Distro == UbuntuLucid || Distro == UbuntuJaunty || +      Distro == UbuntuKarmic) +    ExtraOpts.push_back("--hash-style=both"); + +  if (IsFedora(Distro)) +    ExtraOpts.push_back("--no-add-needed"); + +  if (Distro == DebianSqueeze || IsOpenSuse(Distro) || +      IsFedora(Distro) || Distro == UbuntuLucid || Distro == UbuntuMaverick || +      Distro == UbuntuKarmic) +    ExtraOpts.push_back("--build-id"); + +  Paths.push_back(Base + Suffix); +  if (HasMultilib(Arch, Distro)) { +    if (IsOpenSuse(Distro) && Is32Bits) +      Paths.push_back(Base + "/../../../../" + GccTriple + "/lib/../lib"); +    Paths.push_back(Base + "/../../../../" + Lib); +    Paths.push_back("/lib/../" + Lib); +    Paths.push_back("/usr/lib/../" + Lib); +  } +  if (!Suffix.empty()) +    Paths.push_back(Base); +  if (IsOpenSuse(Distro)) +    Paths.push_back(Base + "/../../../../" + GccTriple + "/lib"); +  Paths.push_back(Base + "/../../.."); +  if (Arch == getArch() && IsUbuntu(Distro)) +    Paths.push_back("/usr/lib/" + GccTriple); +} + +bool Linux::HasNativeLLVMSupport() const { +  return true;  }  Tool &Linux::SelectTool(const Compilation &C, const JobAction &JA) const { @@ -1114,11 +1526,21 @@ Tool &Linux::SelectTool(const Compilation &C, const JobAction &JA) const {    else      Key = JA.getKind(); +  bool UseIntegratedAs = C.getArgs().hasFlag(options::OPT_integrated_as, +                                             options::OPT_no_integrated_as, +                                             IsIntegratedAssemblerDefault()); +    Tool *&T = Tools[Key];    if (!T) {      switch (Key) {      case Action::AssembleJobClass: -      T = new tools::linuxtools::Assemble(*this); break; +      if (UseIntegratedAs) +        T = new tools::ClangAs(*this); +      else +        T = new tools::linuxtools::Assemble(*this); +      break; +    case Action::LinkJobClass: +      T = new tools::linuxtools::Link(*this); break;      default:        T = &Generic_GCC::SelectTool(C, JA);      } @@ -1130,7 +1552,7 @@ Tool &Linux::SelectTool(const Compilation &C, const JobAction &JA) const {  /// DragonFly - DragonFly tool chain which can call as(1) and ld(1) directly.  DragonFly::DragonFly(const HostInfo &Host, const llvm::Triple& Triple) -  : Generic_GCC(Host, Triple) { +  : Generic_ELF(Host, Triple) {    // Path mangling to find libexec    getProgramPaths().push_back(getDriver().getInstalledDir());  | 
