diff options
Diffstat (limited to 'lib/Driver/ToolChains')
| -rw-r--r-- | lib/Driver/ToolChains/BareMetal.cpp | 210 | ||||
| -rw-r--r-- | lib/Driver/ToolChains/BareMetal.h | 90 | ||||
| -rw-r--r-- | lib/Driver/ToolChains/Gnu.cpp | 43 | ||||
| -rw-r--r-- | lib/Driver/ToolChains/Linux.cpp | 43 | ||||
| -rw-r--r-- | lib/Driver/ToolChains/Myriad.cpp | 1 | 
5 files changed, 344 insertions, 43 deletions
diff --git a/lib/Driver/ToolChains/BareMetal.cpp b/lib/Driver/ToolChains/BareMetal.cpp new file mode 100644 index 000000000000..66246f6d71cd --- /dev/null +++ b/lib/Driver/ToolChains/BareMetal.cpp @@ -0,0 +1,210 @@ +//===--- BaremMetal.cpp - Bare Metal ToolChain ------------------*- C++ -*-===// +// +//                     The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#include "BareMetal.h" + +#include "CommonArgs.h" +#include "InputInfo.h" +#include "Gnu.h" + +#include "clang/Basic/VirtualFileSystem.h" +#include "clang/Driver/Compilation.h" +#include "clang/Driver/Driver.h" +#include "clang/Driver/DriverDiagnostic.h" +#include "clang/Driver/Options.h" +#include "llvm/Option/ArgList.h" +#include "llvm/Support/Path.h" +#include "llvm/Support/raw_ostream.h" + +using namespace llvm::opt; +using namespace clang; +using namespace clang::driver; +using namespace clang::driver::tools; +using namespace clang::driver::toolchains; + +BareMetal::BareMetal(const Driver &D, const llvm::Triple &Triple, +                           const ArgList &Args) +    : ToolChain(D, Triple, Args) { +  getProgramPaths().push_back(getDriver().getInstalledDir()); +  if (getDriver().getInstalledDir() != getDriver().Dir) +    getProgramPaths().push_back(getDriver().Dir); +} + +BareMetal::~BareMetal() {} + +/// Is the triple {arm,thumb}-none-none-{eabi,eabihf} ? +static bool isARMBareMetal(const llvm::Triple &Triple) { +  if (Triple.getArch() != llvm::Triple::arm && +      Triple.getArch() != llvm::Triple::thumb) +    return false; + +  if (Triple.getVendor() != llvm::Triple::UnknownVendor) +    return false; + +  if (Triple.getOS() != llvm::Triple::UnknownOS) +    return false; + +  if (Triple.getEnvironment() != llvm::Triple::EABI && +      Triple.getEnvironment() != llvm::Triple::EABIHF) +    return false; + +  return true; +} + +bool BareMetal::handlesTarget(const llvm::Triple &Triple) { +  return isARMBareMetal(Triple); +} + +Tool *BareMetal::buildLinker() const { +  return new tools::baremetal::Linker(*this); +} + +std::string BareMetal::getThreadModel() const { +  return "single"; +} + +bool BareMetal::isThreadModelSupported(const StringRef Model) const { +  return Model == "single"; +} + +std::string BareMetal::getRuntimesDir() const { +  SmallString<128> Dir(getDriver().ResourceDir); +  llvm::sys::path::append(Dir, "lib", "baremetal"); +  return Dir.str(); +} + +void BareMetal::AddClangSystemIncludeArgs(const ArgList &DriverArgs, +                                          ArgStringList &CC1Args) const { +  if (DriverArgs.hasArg(options::OPT_nostdinc)) +    return; + +  if (!DriverArgs.hasArg(options::OPT_nobuiltininc)) { +    SmallString<128> Dir(getDriver().ResourceDir); +    llvm::sys::path::append(Dir, "include"); +    addSystemInclude(DriverArgs, CC1Args, Dir.str()); +  } + +  if (!DriverArgs.hasArg(options::OPT_nostdlibinc)) { +    SmallString<128> Dir(getDriver().SysRoot); +    llvm::sys::path::append(Dir, "include"); +    addSystemInclude(DriverArgs, CC1Args, Dir.str()); +  } +} + +void BareMetal::addClangTargetOptions(const ArgList &DriverArgs, +                                      ArgStringList &CC1Args) const { +  CC1Args.push_back("-nostdsysteminc"); +} + +std::string BareMetal::findLibCxxIncludePath(CXXStdlibType LibType) const { +  StringRef SysRoot = getDriver().SysRoot; +  if (SysRoot.empty()) +    return ""; + +  switch (LibType) { +  case ToolChain::CST_Libcxx: { +    SmallString<128> Dir(SysRoot); +    llvm::sys::path::append(Dir, "include", "c++", "v1"); +    return Dir.str(); +  } +  case ToolChain::CST_Libstdcxx: { +    SmallString<128> Dir(SysRoot); +    llvm::sys::path::append(Dir, "include", "c++"); +    std::error_code EC; +    Generic_GCC::GCCVersion Version = {"", -1, -1, -1, "", "", ""}; +    // Walk the subdirs, and find the one with the newest gcc version: +    for (vfs::directory_iterator LI = +           getDriver().getVFS().dir_begin(Dir.str(), EC), LE; +         !EC && LI != LE; LI = LI.increment(EC)) { +      StringRef VersionText = llvm::sys::path::filename(LI->getName()); +      auto CandidateVersion = Generic_GCC::GCCVersion::Parse(VersionText); +      if (CandidateVersion.Major == -1) +        continue; +      if (CandidateVersion <= Version) +        continue; +      Version = CandidateVersion; +    } +    if (Version.Major == -1) +      return ""; +    llvm::sys::path::append(Dir, Version.Text); +    return Dir.str(); +  } +  } +  llvm_unreachable("unhandled LibType"); +} + +void BareMetal::AddClangCXXStdlibIncludeArgs( +    const ArgList &DriverArgs, ArgStringList &CC1Args) const { +  if (DriverArgs.hasArg(options::OPT_nostdinc) || +      DriverArgs.hasArg(options::OPT_nostdlibinc) || +      DriverArgs.hasArg(options::OPT_nostdincxx)) +    return; + +  std::string Path = findLibCxxIncludePath(GetCXXStdlibType(DriverArgs)); +  if (!Path.empty()) +    addSystemInclude(DriverArgs, CC1Args, Path); +} + +void BareMetal::AddCXXStdlibLibArgs(const ArgList &Args, +                                    ArgStringList &CmdArgs) const { +  switch (GetCXXStdlibType(Args)) { +  case ToolChain::CST_Libcxx: +    CmdArgs.push_back("-lc++"); +    CmdArgs.push_back("-lc++abi"); +    break; +  case ToolChain::CST_Libstdcxx: +    CmdArgs.push_back("-lstdc++"); +    CmdArgs.push_back("-lsupc++"); +    break; +  } +  CmdArgs.push_back("-lunwind"); +} + +void BareMetal::AddLinkRuntimeLib(const ArgList &Args, +                                  ArgStringList &CmdArgs) const { +  CmdArgs.push_back(Args.MakeArgString("-lclang_rt.builtins-" + +                                       getTriple().getArchName() + ".a")); +} + +void baremetal::Linker::ConstructJob(Compilation &C, const JobAction &JA, +                                     const InputInfo &Output, +                                     const InputInfoList &Inputs, +                                     const ArgList &Args, +                                     const char *LinkingOutput) const { +  ArgStringList CmdArgs; + +  auto &TC = static_cast<const toolchains::BareMetal&>(getToolChain()); + +  AddLinkerInputs(TC, Inputs, Args, CmdArgs, JA); + +  CmdArgs.push_back("-Bstatic"); + +  CmdArgs.push_back(Args.MakeArgString("-L" + TC.getRuntimesDir())); + +  Args.AddAllArgs(CmdArgs, {options::OPT_L, options::OPT_T_Group, +                            options::OPT_e, options::OPT_s, options::OPT_t, +                            options::OPT_Z_Flag, options::OPT_r}); + +  if (!Args.hasArg(options::OPT_nostdlib, options::OPT_nodefaultlibs)) { +    if (C.getDriver().CCCIsCXX()) +      TC.AddCXXStdlibLibArgs(Args, CmdArgs); + +    CmdArgs.push_back("-lc"); +    CmdArgs.push_back("-lm"); + +    TC.AddLinkRuntimeLib(Args, CmdArgs); +  } + +  CmdArgs.push_back("-o"); +  CmdArgs.push_back(Output.getFilename()); + +  C.addCommand(llvm::make_unique<Command>(JA, *this, +                                          Args.MakeArgString(TC.GetLinkerPath()), +                                          CmdArgs, Inputs)); +} diff --git a/lib/Driver/ToolChains/BareMetal.h b/lib/Driver/ToolChains/BareMetal.h new file mode 100644 index 000000000000..064c1199735b --- /dev/null +++ b/lib/Driver/ToolChains/BareMetal.h @@ -0,0 +1,90 @@ +//===--- BareMetal.h - Bare Metal Tool and ToolChain -------------*- C++ -*-===// +// +//                     The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_CLANG_LIB_DRIVER_TOOLCHAINS_BAREMETAL_H +#define LLVM_CLANG_LIB_DRIVER_TOOLCHAINS_BAREMETAL_H + +#include "clang/Driver/Tool.h" +#include "clang/Driver/ToolChain.h" + +#include <string> + +namespace clang { +namespace driver { + +namespace toolchains { + +class LLVM_LIBRARY_VISIBILITY BareMetal : public ToolChain { +public: +  BareMetal(const Driver &D, const llvm::Triple &Triple, +            const llvm::opt::ArgList &Args); +  ~BareMetal() override; + +  static bool handlesTarget(const llvm::Triple &Triple); +protected: +  Tool *buildLinker() const override; + +public: +  bool useIntegratedAs() const override { return true; } +  bool isCrossCompiling() const override { return true; } +  bool isPICDefault() const override { return false; } +  bool isPIEDefault() const override { return false; } +  bool isPICDefaultForced() const override { return false; } +  bool SupportsProfiling() const override { return false; } +  bool SupportsObjCGC() const override { return false; } +  std::string getThreadModel() const override; +  bool isThreadModelSupported(const StringRef Model) const override; + +  RuntimeLibType GetDefaultRuntimeLibType() const override { +    return ToolChain::RLT_CompilerRT; +  } +  CXXStdlibType GetDefaultCXXStdlibType() const override { +    return ToolChain::CST_Libcxx; +  } + +  const char *getDefaultLinker() const override { return "ld.lld"; } + +  std::string getRuntimesDir() const; +  void AddClangSystemIncludeArgs(const llvm::opt::ArgList &DriverArgs, +                                 llvm::opt::ArgStringList &CC1Args) const override; +  void addClangTargetOptions(const llvm::opt::ArgList &DriverArgs, +                             llvm::opt::ArgStringList &CC1Args) const override; +  std::string findLibCxxIncludePath(ToolChain::CXXStdlibType LibType) const; +  void AddClangCXXStdlibIncludeArgs( +      const llvm::opt::ArgList &DriverArgs, +      llvm::opt::ArgStringList &CC1Args) const override; +  void AddCXXStdlibLibArgs(const llvm::opt::ArgList &Args, +                           llvm::opt::ArgStringList &CmdArgs) const override; +  void AddLinkRuntimeLib(const llvm::opt::ArgList &Args, +                         llvm::opt::ArgStringList &CmdArgs) const; +}; + +} // namespace toolchains + +namespace tools { +namespace baremetal { + +class LLVM_LIBRARY_VISIBILITY Linker : public Tool { +public: +  Linker(const ToolChain &TC) : Tool("baremetal::Linker", "ld.lld", TC) {} +  bool isLinkJob() const override { return true; } +  bool hasIntegratedCPP() const override { return false; } +  void ConstructJob(Compilation &C, const JobAction &JA, +                    const InputInfo &Output, const InputInfoList &Inputs, +                    const llvm::opt::ArgList &TCArgs, +                    const char *LinkingOutput) const override; +}; + +} // namespace baremetal +} // namespace tools + +} // namespace driver +} // namespace clang + +#endif diff --git a/lib/Driver/ToolChains/Gnu.cpp b/lib/Driver/ToolChains/Gnu.cpp index f1015e62eec8..1a398fd8a773 100644 --- a/lib/Driver/ToolChains/Gnu.cpp +++ b/lib/Driver/ToolChains/Gnu.cpp @@ -1598,6 +1598,49 @@ bool Generic_GCC::GCCVersion::isOlderThan(int RHSMajor, int RHSMinor,    return false;  } +/// \brief Parse a GCCVersion object out of a string of text. +/// +/// This is the primary means of forming GCCVersion objects. +/*static*/ +Generic_GCC::GCCVersion Generic_GCC::GCCVersion::Parse(StringRef VersionText) { +  const GCCVersion BadVersion = {VersionText.str(), -1, -1, -1, "", "", ""}; +  std::pair<StringRef, StringRef> First = VersionText.split('.'); +  std::pair<StringRef, StringRef> Second = First.second.split('.'); + +  GCCVersion GoodVersion = {VersionText.str(), -1, -1, -1, "", "", ""}; +  if (First.first.getAsInteger(10, GoodVersion.Major) || GoodVersion.Major < 0) +    return BadVersion; +  GoodVersion.MajorStr = First.first.str(); +  if (First.second.empty()) +    return GoodVersion; +  if (Second.first.getAsInteger(10, GoodVersion.Minor) || GoodVersion.Minor < 0) +    return BadVersion; +  GoodVersion.MinorStr = Second.first.str(); + +  // First look for a number prefix and parse that if present. Otherwise just +  // stash the entire patch string in the suffix, and leave the number +  // unspecified. This covers versions strings such as: +  //   5        (handled above) +  //   4.4 +  //   4.4.0 +  //   4.4.x +  //   4.4.2-rc4 +  //   4.4.x-patched +  // And retains any patch number it finds. +  StringRef PatchText = GoodVersion.PatchSuffix = Second.second.str(); +  if (!PatchText.empty()) { +    if (size_t EndNumber = PatchText.find_first_not_of("0123456789")) { +      // Try to parse the number and any suffix. +      if (PatchText.slice(0, EndNumber).getAsInteger(10, GoodVersion.Patch) || +          GoodVersion.Patch < 0) +        return BadVersion; +      GoodVersion.PatchSuffix = PatchText.substr(EndNumber); +    } +  } + +  return GoodVersion; +} +  static llvm::StringRef getGCCToolchainDir(const ArgList &Args) {    const Arg *A = Args.getLastArg(clang::driver::options::OPT_gcc_toolchain);    if (A) diff --git a/lib/Driver/ToolChains/Linux.cpp b/lib/Driver/ToolChains/Linux.cpp index 50443a125244..9da366eb55fe 100644 --- a/lib/Driver/ToolChains/Linux.cpp +++ b/lib/Driver/ToolChains/Linux.cpp @@ -372,49 +372,6 @@ Linux::Linux(const Driver &D, const llvm::Triple &Triple, const ArgList &Args)    addPathIfExists(D, SysRoot + "/usr/lib", Paths);  } -/// \brief Parse a GCCVersion object out of a string of text. -/// -/// This is the primary means of forming GCCVersion objects. -/*static*/ -Generic_GCC::GCCVersion Linux::GCCVersion::Parse(StringRef VersionText) { -  const GCCVersion BadVersion = {VersionText.str(), -1, -1, -1, "", "", ""}; -  std::pair<StringRef, StringRef> First = VersionText.split('.'); -  std::pair<StringRef, StringRef> Second = First.second.split('.'); - -  GCCVersion GoodVersion = {VersionText.str(), -1, -1, -1, "", "", ""}; -  if (First.first.getAsInteger(10, GoodVersion.Major) || GoodVersion.Major < 0) -    return BadVersion; -  GoodVersion.MajorStr = First.first.str(); -  if (First.second.empty()) -    return GoodVersion; -  if (Second.first.getAsInteger(10, GoodVersion.Minor) || GoodVersion.Minor < 0) -    return BadVersion; -  GoodVersion.MinorStr = Second.first.str(); - -  // First look for a number prefix and parse that if present. Otherwise just -  // stash the entire patch string in the suffix, and leave the number -  // unspecified. This covers versions strings such as: -  //   5        (handled above) -  //   4.4 -  //   4.4.0 -  //   4.4.x -  //   4.4.2-rc4 -  //   4.4.x-patched -  // And retains any patch number it finds. -  StringRef PatchText = GoodVersion.PatchSuffix = Second.second.str(); -  if (!PatchText.empty()) { -    if (size_t EndNumber = PatchText.find_first_not_of("0123456789")) { -      // Try to parse the number and any suffix. -      if (PatchText.slice(0, EndNumber).getAsInteger(10, GoodVersion.Patch) || -          GoodVersion.Patch < 0) -        return BadVersion; -      GoodVersion.PatchSuffix = PatchText.substr(EndNumber); -    } -  } - -  return GoodVersion; -} -  bool Linux::HasNativeLLVMSupport() const { return true; }  Tool *Linux::buildLinker() const { return new tools::gnutools::Linker(*this); } diff --git a/lib/Driver/ToolChains/Myriad.cpp b/lib/Driver/ToolChains/Myriad.cpp index f70ce93c45ce..6fdb5a2248dd 100644 --- a/lib/Driver/ToolChains/Myriad.cpp +++ b/lib/Driver/ToolChains/Myriad.cpp @@ -217,6 +217,7 @@ MyriadToolChain::MyriadToolChain(const Driver &D, const llvm::Triple &Triple,    default:      D.Diag(clang::diag::err_target_unsupported_arch)          << Triple.getArchName() << "myriad"; +    LLVM_FALLTHROUGH;    case llvm::Triple::sparc:    case llvm::Triple::sparcel:    case llvm::Triple::shave:  | 
