• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 //===-- BareMetal.cpp - Bare Metal ToolChain --------------------*- C++ -*-===//
2 //
3 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4 // See https://llvm.org/LICENSE.txt for license information.
5 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6 //
7 //===----------------------------------------------------------------------===//
8 
9 #include "BareMetal.h"
10 
11 #include "CommonArgs.h"
12 #include "InputInfo.h"
13 #include "Gnu.h"
14 
15 #include "clang/Driver/Compilation.h"
16 #include "clang/Driver/Driver.h"
17 #include "clang/Driver/DriverDiagnostic.h"
18 #include "clang/Driver/Options.h"
19 #include "llvm/Option/ArgList.h"
20 #include "llvm/Support/Path.h"
21 #include "llvm/Support/VirtualFileSystem.h"
22 #include "llvm/Support/raw_ostream.h"
23 
24 using namespace llvm::opt;
25 using namespace clang;
26 using namespace clang::driver;
27 using namespace clang::driver::tools;
28 using namespace clang::driver::toolchains;
29 
BareMetal(const Driver & D,const llvm::Triple & Triple,const ArgList & Args)30 BareMetal::BareMetal(const Driver &D, const llvm::Triple &Triple,
31                            const ArgList &Args)
32     : ToolChain(D, Triple, Args) {
33   getProgramPaths().push_back(getDriver().getInstalledDir());
34   if (getDriver().getInstalledDir() != getDriver().Dir)
35     getProgramPaths().push_back(getDriver().Dir);
36   SmallString<128> SysRoot(computeSysRoot());
37   if (!SysRoot.empty()) {
38     llvm::sys::path::append(SysRoot, "lib");
39     getFilePaths().push_back(std::string(SysRoot));
40   }
41 }
42 
43 /// Is the triple {arm,thumb}-none-none-{eabi,eabihf} ?
isARMBareMetal(const llvm::Triple & Triple)44 static bool isARMBareMetal(const llvm::Triple &Triple) {
45   if (Triple.getArch() != llvm::Triple::arm &&
46       Triple.getArch() != llvm::Triple::thumb)
47     return false;
48 
49   if (Triple.getVendor() != llvm::Triple::UnknownVendor)
50     return false;
51 
52   if (Triple.getOS() != llvm::Triple::UnknownOS)
53     return false;
54 
55   if (Triple.getEnvironment() != llvm::Triple::EABI &&
56       Triple.getEnvironment() != llvm::Triple::EABIHF)
57     return false;
58 
59   return true;
60 }
61 
isRISCVBareMetal(const llvm::Triple & Triple)62 static bool isRISCVBareMetal(const llvm::Triple &Triple) {
63   if (Triple.getArch() != llvm::Triple::riscv32 &&
64       Triple.getArch() != llvm::Triple::riscv64)
65     return false;
66 
67   if (Triple.getVendor() != llvm::Triple::UnknownVendor)
68     return false;
69 
70   if (Triple.getOS() != llvm::Triple::UnknownOS)
71     return false;
72 
73   return Triple.getEnvironmentName() == "elf";
74 }
75 
handlesTarget(const llvm::Triple & Triple)76 bool BareMetal::handlesTarget(const llvm::Triple &Triple) {
77   return isARMBareMetal(Triple) || isRISCVBareMetal(Triple);
78 }
79 
buildLinker() const80 Tool *BareMetal::buildLinker() const {
81   return new tools::baremetal::Linker(*this);
82 }
83 
getCompilerRTPath() const84 std::string BareMetal::getCompilerRTPath() const { return getRuntimesDir(); }
85 
getCompilerRTBasename(const llvm::opt::ArgList &,StringRef,FileType,bool) const86 std::string BareMetal::getCompilerRTBasename(const llvm::opt::ArgList &,
87                                              StringRef, FileType, bool) const {
88   return ("libclang_rt.builtins-" + getTriple().getArchName() + ".a").str();
89 }
90 
getRuntimesDir() const91 std::string BareMetal::getRuntimesDir() const {
92   SmallString<128> Dir(getDriver().ResourceDir);
93   llvm::sys::path::append(Dir, "lib", "baremetal");
94   return std::string(Dir.str());
95 }
96 
computeSysRoot() const97 std::string BareMetal::computeSysRoot() const {
98   if (!getDriver().SysRoot.empty())
99     return getDriver().SysRoot;
100 
101   SmallString<128> SysRootDir;
102   llvm::sys::path::append(SysRootDir, getDriver().Dir, "../lib/clang-runtimes",
103                           getDriver().getTargetTriple());
104 
105   return std::string(SysRootDir);
106 }
107 
AddClangSystemIncludeArgs(const ArgList & DriverArgs,ArgStringList & CC1Args) const108 void BareMetal::AddClangSystemIncludeArgs(const ArgList &DriverArgs,
109                                           ArgStringList &CC1Args) const {
110   if (DriverArgs.hasArg(options::OPT_nostdinc))
111     return;
112 
113   if (!DriverArgs.hasArg(options::OPT_nobuiltininc)) {
114     SmallString<128> Dir(getDriver().ResourceDir);
115     llvm::sys::path::append(Dir, "include");
116     addSystemInclude(DriverArgs, CC1Args, Dir.str());
117   }
118 
119   if (!DriverArgs.hasArg(options::OPT_nostdlibinc)) {
120     SmallString<128> Dir(computeSysRoot());
121     if (!Dir.empty()) {
122       llvm::sys::path::append(Dir, "include");
123       addSystemInclude(DriverArgs, CC1Args, Dir.str());
124     }
125   }
126 }
127 
addClangTargetOptions(const ArgList & DriverArgs,ArgStringList & CC1Args,Action::OffloadKind) const128 void BareMetal::addClangTargetOptions(const ArgList &DriverArgs,
129                                       ArgStringList &CC1Args,
130                                       Action::OffloadKind) const {
131   CC1Args.push_back("-nostdsysteminc");
132 }
133 
AddClangCXXStdlibIncludeArgs(const ArgList & DriverArgs,ArgStringList & CC1Args) const134 void BareMetal::AddClangCXXStdlibIncludeArgs(
135     const ArgList &DriverArgs, ArgStringList &CC1Args) const {
136   if (DriverArgs.hasArg(options::OPT_nostdinc) ||
137       DriverArgs.hasArg(options::OPT_nostdlibinc) ||
138       DriverArgs.hasArg(options::OPT_nostdincxx))
139     return;
140 
141   std::string SysRoot(computeSysRoot());
142   if (SysRoot.empty())
143     return;
144 
145   switch (GetCXXStdlibType(DriverArgs)) {
146   case ToolChain::CST_Libcxx: {
147     SmallString<128> Dir(SysRoot);
148     llvm::sys::path::append(Dir, "include", "c++", "v1");
149     addSystemInclude(DriverArgs, CC1Args, Dir.str());
150     break;
151   }
152   case ToolChain::CST_Libstdcxx: {
153     SmallString<128> Dir(SysRoot);
154     llvm::sys::path::append(Dir, "include", "c++");
155     std::error_code EC;
156     Generic_GCC::GCCVersion Version = {"", -1, -1, -1, "", "", ""};
157     // Walk the subdirs, and find the one with the newest gcc version:
158     for (llvm::vfs::directory_iterator
159              LI = getDriver().getVFS().dir_begin(Dir.str(), EC),
160              LE;
161          !EC && LI != LE; LI = LI.increment(EC)) {
162       StringRef VersionText = llvm::sys::path::filename(LI->path());
163       auto CandidateVersion = Generic_GCC::GCCVersion::Parse(VersionText);
164       if (CandidateVersion.Major == -1)
165         continue;
166       if (CandidateVersion <= Version)
167         continue;
168       Version = CandidateVersion;
169     }
170     if (Version.Major == -1)
171       return;
172     llvm::sys::path::append(Dir, Version.Text);
173     addSystemInclude(DriverArgs, CC1Args, Dir.str());
174     break;
175   }
176   }
177 }
178 
AddCXXStdlibLibArgs(const ArgList & Args,ArgStringList & CmdArgs) const179 void BareMetal::AddCXXStdlibLibArgs(const ArgList &Args,
180                                     ArgStringList &CmdArgs) const {
181   switch (GetCXXStdlibType(Args)) {
182   case ToolChain::CST_Libcxx:
183     CmdArgs.push_back("-lc++");
184     CmdArgs.push_back("-lc++abi");
185     break;
186   case ToolChain::CST_Libstdcxx:
187     CmdArgs.push_back("-lstdc++");
188     CmdArgs.push_back("-lsupc++");
189     break;
190   }
191   CmdArgs.push_back("-lunwind");
192 }
193 
AddLinkRuntimeLib(const ArgList & Args,ArgStringList & CmdArgs) const194 void BareMetal::AddLinkRuntimeLib(const ArgList &Args,
195                                   ArgStringList &CmdArgs) const {
196   ToolChain::RuntimeLibType RLT = GetRuntimeLibType(Args);
197   switch (RLT) {
198   case ToolChain::RLT_CompilerRT:
199     CmdArgs.push_back(
200         Args.MakeArgString("-lclang_rt.builtins-" + getTriple().getArchName()));
201     return;
202   case ToolChain::RLT_Libgcc:
203     CmdArgs.push_back("-lgcc");
204     return;
205   }
206   llvm_unreachable("Unhandled RuntimeLibType.");
207 }
208 
ConstructJob(Compilation & C,const JobAction & JA,const InputInfo & Output,const InputInfoList & Inputs,const ArgList & Args,const char * LinkingOutput) const209 void baremetal::Linker::ConstructJob(Compilation &C, const JobAction &JA,
210                                      const InputInfo &Output,
211                                      const InputInfoList &Inputs,
212                                      const ArgList &Args,
213                                      const char *LinkingOutput) const {
214   ArgStringList CmdArgs;
215 
216   auto &TC = static_cast<const toolchains::BareMetal&>(getToolChain());
217 
218   AddLinkerInputs(TC, Inputs, Args, CmdArgs, JA);
219 
220   CmdArgs.push_back("-Bstatic");
221 
222   CmdArgs.push_back(Args.MakeArgString("-L" + TC.getRuntimesDir()));
223 
224   TC.AddFilePathLibArgs(Args, CmdArgs);
225   Args.AddAllArgs(CmdArgs, {options::OPT_L, options::OPT_T_Group,
226                             options::OPT_e, options::OPT_s, options::OPT_t,
227                             options::OPT_Z_Flag, options::OPT_r});
228 
229   if (TC.ShouldLinkCXXStdlib(Args))
230     TC.AddCXXStdlibLibArgs(Args, CmdArgs);
231   if (!Args.hasArg(options::OPT_nostdlib, options::OPT_nodefaultlibs)) {
232     CmdArgs.push_back("-lc");
233     CmdArgs.push_back("-lm");
234 
235     TC.AddLinkRuntimeLib(Args, CmdArgs);
236   }
237 
238   CmdArgs.push_back("-o");
239   CmdArgs.push_back(Output.getFilename());
240 
241   C.addCommand(std::make_unique<Command>(JA, *this, ResponseFileSupport::None(),
242                                          Args.MakeArgString(TC.GetLinkerPath()),
243                                          CmdArgs, Inputs, Output));
244 }
245