|  | //===--- 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::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, | 
|  | Action::OffloadKind) const { | 
|  | CC1Args.push_back("-nostdsysteminc"); | 
|  | } | 
|  |  | 
|  | 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; | 
|  |  | 
|  | StringRef SysRoot = getDriver().SysRoot; | 
|  | if (SysRoot.empty()) | 
|  | return; | 
|  |  | 
|  | switch (GetCXXStdlibType(DriverArgs)) { | 
|  | case ToolChain::CST_Libcxx: { | 
|  | SmallString<128> Dir(SysRoot); | 
|  | llvm::sys::path::append(Dir, "include", "c++", "v1"); | 
|  | addSystemInclude(DriverArgs, CC1Args, Dir.str()); | 
|  | break; | 
|  | } | 
|  | 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); | 
|  | addSystemInclude(DriverArgs, CC1Args, Dir.str()); | 
|  | break; | 
|  | } | 
|  | } | 
|  | } | 
|  |  | 
|  | 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 (TC.ShouldLinkCXXStdlib(Args)) | 
|  | TC.AddCXXStdlibLibArgs(Args, CmdArgs); | 
|  | if (!Args.hasArg(options::OPT_nostdlib, options::OPT_nodefaultlibs)) { | 
|  | 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)); | 
|  | } |