clang  16.0.0git
BareMetal.cpp
Go to the documentation of this file.
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 "Gnu.h"
13 #include "clang/Driver/InputInfo.h"
14 
15 #include "Arch/RISCV.h"
17 #include "clang/Driver/Driver.h"
19 #include "clang/Driver/Options.h"
20 #include "llvm/Option/ArgList.h"
21 #include "llvm/Support/Path.h"
22 #include "llvm/Support/VirtualFileSystem.h"
23 #include "llvm/Support/raw_ostream.h"
24 
25 using namespace llvm::opt;
26 using namespace clang;
27 using namespace clang::driver;
28 using namespace clang::driver::tools;
29 using namespace clang::driver::toolchains;
30 
31 static Multilib makeMultilib(StringRef commonSuffix) {
32  return Multilib(commonSuffix, commonSuffix, commonSuffix);
33 }
34 
35 static bool findRISCVMultilibs(const Driver &D,
36  const llvm::Triple &TargetTriple,
37  const ArgList &Args, DetectedMultilibs &Result) {
39  StringRef Arch = riscv::getRISCVArch(Args, TargetTriple);
40  StringRef Abi = tools::riscv::getRISCVABI(Args, TargetTriple);
41 
42  if (TargetTriple.isRISCV64()) {
43  Multilib Imac = makeMultilib("").flag("+march=rv64imac").flag("+mabi=lp64");
44  Multilib Imafdc = makeMultilib("/rv64imafdc/lp64d")
45  .flag("+march=rv64imafdc")
46  .flag("+mabi=lp64d");
47 
48  // Multilib reuse
49  bool UseImafdc =
50  (Arch == "rv64imafdc") || (Arch == "rv64gc"); // gc => imafdc
51 
52  addMultilibFlag((Arch == "rv64imac"), "march=rv64imac", Flags);
53  addMultilibFlag(UseImafdc, "march=rv64imafdc", Flags);
54  addMultilibFlag(Abi == "lp64", "mabi=lp64", Flags);
55  addMultilibFlag(Abi == "lp64d", "mabi=lp64d", Flags);
56 
57  Result.Multilibs = MultilibSet().Either(Imac, Imafdc);
58  return Result.Multilibs.select(Flags, Result.SelectedMultilib);
59  }
60  if (TargetTriple.isRISCV32()) {
61  Multilib Imac =
62  makeMultilib("").flag("+march=rv32imac").flag("+mabi=ilp32");
63  Multilib I =
64  makeMultilib("/rv32i/ilp32").flag("+march=rv32i").flag("+mabi=ilp32");
65  Multilib Im =
66  makeMultilib("/rv32im/ilp32").flag("+march=rv32im").flag("+mabi=ilp32");
67  Multilib Iac = makeMultilib("/rv32iac/ilp32")
68  .flag("+march=rv32iac")
69  .flag("+mabi=ilp32");
70  Multilib Imafc = makeMultilib("/rv32imafc/ilp32f")
71  .flag("+march=rv32imafc")
72  .flag("+mabi=ilp32f");
73 
74  // Multilib reuse
75  bool UseI = (Arch == "rv32i") || (Arch == "rv32ic"); // ic => i
76  bool UseIm = (Arch == "rv32im") || (Arch == "rv32imc"); // imc => im
77  bool UseImafc = (Arch == "rv32imafc") || (Arch == "rv32imafdc") ||
78  (Arch == "rv32gc"); // imafdc,gc => imafc
79 
80  addMultilibFlag(UseI, "march=rv32i", Flags);
81  addMultilibFlag(UseIm, "march=rv32im", Flags);
82  addMultilibFlag((Arch == "rv32iac"), "march=rv32iac", Flags);
83  addMultilibFlag((Arch == "rv32imac"), "march=rv32imac", Flags);
84  addMultilibFlag(UseImafc, "march=rv32imafc", Flags);
85  addMultilibFlag(Abi == "ilp32", "mabi=ilp32", Flags);
86  addMultilibFlag(Abi == "ilp32f", "mabi=ilp32f", Flags);
87 
88  Result.Multilibs = MultilibSet().Either(I, Im, Iac, Imac, Imafc);
89  return Result.Multilibs.select(Flags, Result.SelectedMultilib);
90  }
91  return false;
92 }
93 
94 BareMetal::BareMetal(const Driver &D, const llvm::Triple &Triple,
95  const ArgList &Args)
96  : ToolChain(D, Triple, Args) {
97  getProgramPaths().push_back(getDriver().getInstalledDir());
98  if (getDriver().getInstalledDir() != getDriver().Dir)
99  getProgramPaths().push_back(getDriver().Dir);
100 
101  findMultilibs(D, Triple, Args);
102  SmallString<128> SysRoot(computeSysRoot());
103  if (!SysRoot.empty()) {
104  llvm::sys::path::append(SysRoot, "lib");
105  getFilePaths().push_back(std::string(SysRoot));
106  }
107 }
108 
109 /// Is the triple {arm,thumb}-none-none-{eabi,eabihf} ?
110 static bool isARMBareMetal(const llvm::Triple &Triple) {
111  if (Triple.getArch() != llvm::Triple::arm &&
112  Triple.getArch() != llvm::Triple::thumb)
113  return false;
114 
115  if (Triple.getVendor() != llvm::Triple::UnknownVendor)
116  return false;
117 
118  if (Triple.getOS() != llvm::Triple::UnknownOS)
119  return false;
120 
121  if (Triple.getEnvironment() != llvm::Triple::EABI &&
122  Triple.getEnvironment() != llvm::Triple::EABIHF)
123  return false;
124 
125  return true;
126 }
127 
128 /// Is the triple aarch64-none-elf?
129 static bool isAArch64BareMetal(const llvm::Triple &Triple) {
130  if (Triple.getArch() != llvm::Triple::aarch64)
131  return false;
132 
133  if (Triple.getVendor() != llvm::Triple::UnknownVendor)
134  return false;
135 
136  if (Triple.getOS() != llvm::Triple::UnknownOS)
137  return false;
138 
139  return Triple.getEnvironmentName() == "elf";
140 }
141 
142 static bool isRISCVBareMetal(const llvm::Triple &Triple) {
143  if (!Triple.isRISCV())
144  return false;
145 
146  if (Triple.getVendor() != llvm::Triple::UnknownVendor)
147  return false;
148 
149  if (Triple.getOS() != llvm::Triple::UnknownOS)
150  return false;
151 
152  return Triple.getEnvironmentName() == "elf";
153 }
154 
155 void BareMetal::findMultilibs(const Driver &D, const llvm::Triple &Triple,
156  const ArgList &Args) {
157  DetectedMultilibs Result;
158  if (isRISCVBareMetal(Triple)) {
159  if (findRISCVMultilibs(D, Triple, Args, Result)) {
160  SelectedMultilib = Result.SelectedMultilib;
161  Multilibs = Result.Multilibs;
162  }
163  }
164 }
165 
166 bool BareMetal::handlesTarget(const llvm::Triple &Triple) {
167  return isARMBareMetal(Triple) || isAArch64BareMetal(Triple) ||
168  isRISCVBareMetal(Triple);
169 }
170 
172  return new tools::baremetal::Linker(*this);
173 }
174 
176  if (!getDriver().SysRoot.empty())
178 
179  SmallString<128> SysRootDir;
180  llvm::sys::path::append(SysRootDir, getDriver().Dir, "../lib/clang-runtimes",
181  getDriver().getTargetTriple());
182 
183  SysRootDir += SelectedMultilib.osSuffix();
184  return std::string(SysRootDir);
185 }
186 
187 void BareMetal::AddClangSystemIncludeArgs(const ArgList &DriverArgs,
188  ArgStringList &CC1Args) const {
189  if (DriverArgs.hasArg(options::OPT_nostdinc))
190  return;
191 
192  if (!DriverArgs.hasArg(options::OPT_nobuiltininc)) {
193  SmallString<128> Dir(getDriver().ResourceDir);
194  llvm::sys::path::append(Dir, "include");
195  addSystemInclude(DriverArgs, CC1Args, Dir.str());
196  }
197 
198  if (!DriverArgs.hasArg(options::OPT_nostdlibinc)) {
200  if (!Dir.empty()) {
201  llvm::sys::path::append(Dir, "include");
202  addSystemInclude(DriverArgs, CC1Args, Dir.str());
203  }
204  }
205 }
206 
207 void BareMetal::addClangTargetOptions(const ArgList &DriverArgs,
208  ArgStringList &CC1Args,
209  Action::OffloadKind) const {
210  CC1Args.push_back("-nostdsysteminc");
211 }
212 
213 void BareMetal::AddClangCXXStdlibIncludeArgs(const ArgList &DriverArgs,
214  ArgStringList &CC1Args) const {
215  if (DriverArgs.hasArg(options::OPT_nostdinc) ||
216  DriverArgs.hasArg(options::OPT_nostdlibinc) ||
217  DriverArgs.hasArg(options::OPT_nostdincxx))
218  return;
219 
220  const Driver &D = getDriver();
221  std::string SysRoot(computeSysRoot());
222  if (SysRoot.empty())
223  return;
224 
225  switch (GetCXXStdlibType(DriverArgs)) {
226  case ToolChain::CST_Libcxx: {
227  // First check sysroot/usr/include/c++/v1 if it exists.
228  SmallString<128> TargetDir(SysRoot);
229  llvm::sys::path::append(TargetDir, "usr", "include", "c++", "v1");
230  if (D.getVFS().exists(TargetDir)) {
231  addSystemInclude(DriverArgs, CC1Args, TargetDir.str());
232  break;
233  }
234  // Add generic path if nothing else succeeded so far.
235  SmallString<128> Dir(SysRoot);
236  llvm::sys::path::append(Dir, "include", "c++", "v1");
237  addSystemInclude(DriverArgs, CC1Args, Dir.str());
238  break;
239  }
241  SmallString<128> Dir(SysRoot);
242  llvm::sys::path::append(Dir, "include", "c++");
243  std::error_code EC;
244  Generic_GCC::GCCVersion Version = {"", -1, -1, -1, "", "", ""};
245  // Walk the subdirs, and find the one with the newest gcc version:
246  for (llvm::vfs::directory_iterator LI = D.getVFS().dir_begin(Dir.str(), EC),
247  LE;
248  !EC && LI != LE; LI = LI.increment(EC)) {
249  StringRef VersionText = llvm::sys::path::filename(LI->path());
250  auto CandidateVersion = Generic_GCC::GCCVersion::Parse(VersionText);
251  if (CandidateVersion.Major == -1)
252  continue;
253  if (CandidateVersion <= Version)
254  continue;
255  Version = CandidateVersion;
256  }
257  if (Version.Major == -1)
258  return;
259  llvm::sys::path::append(Dir, Version.Text);
260  addSystemInclude(DriverArgs, CC1Args, Dir.str());
261  break;
262  }
263  }
264 }
265 
266 void BareMetal::AddCXXStdlibLibArgs(const ArgList &Args,
267  ArgStringList &CmdArgs) const {
268  switch (GetCXXStdlibType(Args)) {
270  CmdArgs.push_back("-lc++");
271  if (Args.hasArg(options::OPT_fexperimental_library))
272  CmdArgs.push_back("-lc++experimental");
273  CmdArgs.push_back("-lc++abi");
274  break;
276  CmdArgs.push_back("-lstdc++");
277  CmdArgs.push_back("-lsupc++");
278  break;
279  }
280  CmdArgs.push_back("-lunwind");
281 }
282 
283 void BareMetal::AddLinkRuntimeLib(const ArgList &Args,
284  ArgStringList &CmdArgs) const {
286  switch (RLT) {
288  const std::string FileName = getCompilerRT(Args, "builtins");
289  llvm::StringRef BaseName = llvm::sys::path::filename(FileName);
290  BaseName.consume_front("lib");
291  BaseName.consume_back(".a");
292  CmdArgs.push_back(Args.MakeArgString("-l" + BaseName));
293  return;
294  }
296  CmdArgs.push_back("-lgcc");
297  return;
298  }
299  llvm_unreachable("Unhandled RuntimeLibType.");
300 }
301 
302 void baremetal::Linker::ConstructJob(Compilation &C, const JobAction &JA,
303  const InputInfo &Output,
304  const InputInfoList &Inputs,
305  const ArgList &Args,
306  const char *LinkingOutput) const {
307  ArgStringList CmdArgs;
308 
309  auto &TC = static_cast<const toolchains::BareMetal &>(getToolChain());
310 
311  AddLinkerInputs(TC, Inputs, Args, CmdArgs, JA);
312 
313  CmdArgs.push_back("-Bstatic");
314 
315  Args.AddAllArgs(CmdArgs, {options::OPT_L, options::OPT_T_Group,
316  options::OPT_e, options::OPT_s, options::OPT_t,
317  options::OPT_Z_Flag, options::OPT_r});
318 
319  TC.AddFilePathLibArgs(Args, CmdArgs);
320 
321  for (const auto &LibPath : TC.getLibraryPaths())
322  CmdArgs.push_back(Args.MakeArgString(llvm::Twine("-L", LibPath)));
323 
324  const std::string FileName = TC.getCompilerRT(Args, "builtins");
325  llvm::SmallString<128> PathBuf{FileName};
326  llvm::sys::path::remove_filename(PathBuf);
327  CmdArgs.push_back(Args.MakeArgString("-L" + PathBuf));
328 
329  if (TC.ShouldLinkCXXStdlib(Args))
330  TC.AddCXXStdlibLibArgs(Args, CmdArgs);
331 
332  if (!Args.hasArg(options::OPT_nostdlib, options::OPT_nodefaultlibs)) {
333  CmdArgs.push_back("-lc");
334  CmdArgs.push_back("-lm");
335 
336  TC.AddLinkRuntimeLib(Args, CmdArgs);
337  }
338 
339  CmdArgs.push_back("-o");
340  CmdArgs.push_back(Output.getFilename());
341 
342  C.addCommand(std::make_unique<Command>(JA, *this, ResponseFileSupport::None(),
343  Args.MakeArgString(TC.GetLinkerPath()),
344  CmdArgs, Inputs, Output));
345 }
clang::driver::toolchains
Definition: AIX.h:55
clang::driver::Multilib::flags_list
std::vector< std::string > flags_list
Definition: Multilib.h:30
makeMultilib
static Multilib makeMultilib(StringRef commonSuffix)
Definition: BareMetal.cpp:31
clang::driver::ToolChain::getCompilerRT
virtual std::string getCompilerRT(const llvm::opt::ArgList &Args, StringRef Component, FileType Type=ToolChain::FT_Static) const
Definition: ToolChain.cpp:516
clang::driver::MultilibSet::Either
MultilibSet & Either(const Multilib &M1, const Multilib &M2)
Add a set of mutually incompatible Multilib segments.
Definition: Multilib.cpp:152
clang::driver::ToolChain::getProgramPaths
path_list & getProgramPaths()
Definition: ToolChain.h:277
Driver.h
string
string(SUBSTRING ${CMAKE_CURRENT_BINARY_DIR} 0 ${PATH_LIB_START} PATH_HEAD) string(SUBSTRING $
Definition: CMakeLists.txt:22
clang::driver::MultilibSet
Definition: Multilib.h:114
llvm::SmallVector
Definition: LLVM.h:38
clang::driver::tools
Definition: AIX.h:17
clang::driver::ToolChain::getDriver
const Driver & getDriver() const
Definition: ToolChain.h:232
isRISCVBareMetal
static bool isRISCVBareMetal(const llvm::Triple &Triple)
Definition: BareMetal.cpp:142
clang::driver::InputInfo
InputInfo - Wrapper for information about an input source.
Definition: InputInfo.h:22
RISCV.h
clang::driver::ToolChain::RuntimeLibType
RuntimeLibType
Definition: ToolChain.h:100
InputInfo.h
clang::driver::tools::riscv::getRISCVArch
StringRef getRISCVArch(const llvm::opt::ArgList &Args, const llvm::Triple &Triple)
Definition: RISCV.cpp:230
clang::driver::tools::AddLinkerInputs
void AddLinkerInputs(const ToolChain &TC, const InputInfoList &Inputs, const llvm::opt::ArgList &Args, llvm::opt::ArgStringList &CmdArgs, const JobAction &JA)
clang::driver::toolchains::Generic_GCC::GCCVersion
Struct to store and manipulate GCC versions.
Definition: Gnu.h:161
clang::driver::ToolChain::getFilePaths
path_list & getFilePaths()
Definition: ToolChain.h:274
clang::driver::tools::baremetal::Linker
Definition: BareMetal.h:80
clang::driver::toolchains::BareMetal::AddClangSystemIncludeArgs
void AddClangSystemIncludeArgs(const llvm::opt::ArgList &DriverArgs, llvm::opt::ArgStringList &CC1Args) const override
Add the clang cc1 arguments for system include paths.
Definition: BareMetal.cpp:187
clang::driver::Tool
Tool - Information on a specific compilation tool.
Definition: Tool.h:32
Options.h
clang::driver::toolchains::Generic_GCC::GCCVersion::Text
std::string Text
The unparsed text of the version.
Definition: Gnu.h:163
clang::driver::Multilib::osSuffix
const std::string & osSuffix() const
Get the detected os path suffix for the multi-arch target variant.
Definition: Multilib.h:56
clang::interp::LE
bool LE(InterpState &S, CodePtr OpPC)
Definition: Interp.h:504
llvm::opt
Definition: DiagnosticOptions.h:19
DriverDiagnostic.h
clang::driver::ToolChain::RLT_Libgcc
@ RLT_Libgcc
Definition: ToolChain.h:102
BareMetal.h
clang::driver::toolchains::BareMetal::AddClangCXXStdlibIncludeArgs
void AddClangCXXStdlibIncludeArgs(const llvm::opt::ArgList &DriverArgs, llvm::opt::ArgStringList &CC1Args) const override
AddClangCXXStdlibIncludeArgs - Add the clang -cc1 level arguments to set the include paths to use for...
Definition: BareMetal.cpp:213
llvm::SmallString< 128 >
clang::driver::ToolChain::SelectedMultilib
Multilib SelectedMultilib
Definition: ToolChain.h:190
clang::driver::Driver::SysRoot
std::string SysRoot
sysroot, if present
Definition: Driver.h:181
clang::driver::Multilib
This corresponds to a single GCC Multilib, or a segment of one controlled by a command line flag.
Definition: Multilib.h:28
clang::driver::ToolChain::CST_Libcxx
@ CST_Libcxx
Definition: ToolChain.h:96
findRISCVMultilibs
static bool findRISCVMultilibs(const Driver &D, const llvm::Triple &TargetTriple, const ArgList &Args, DetectedMultilibs &Result)
Definition: BareMetal.cpp:35
clang::driver::toolchains::Generic_GCC::GCCVersion::Parse
static GCCVersion Parse(StringRef VersionText)
Parse a GCCVersion object out of a string of text.
Definition: Gnu.cpp:1926
clang::driver::ToolChain::CST_Libstdcxx
@ CST_Libstdcxx
Definition: ToolChain.h:97
clang::driver::toolchains::BareMetal::buildLinker
Tool * buildLinker() const override
Definition: BareMetal.cpp:171
clang::driver::toolchains::BareMetal
Definition: BareMetal.h:22
clang::driver::ToolChain::GetRuntimeLibType
virtual RuntimeLibType GetRuntimeLibType(const llvm::opt::ArgList &Args) const
Definition: ToolChain.cpp:831
Compilation.h
clang::driver::toolchains::BareMetal::findMultilibs
void findMultilibs(const Driver &D, const llvm::Triple &Triple, const llvm::opt::ArgList &Args)
Definition: BareMetal.cpp:155
Gnu.h
clang::driver::ToolChain
ToolChain - Access to tools for a single platform.
Definition: ToolChain.h:91
clang::driver::ToolChain::RLT_CompilerRT
@ RLT_CompilerRT
Definition: ToolChain.h:101
isAArch64BareMetal
static bool isAArch64BareMetal(const llvm::Triple &Triple)
Is the triple aarch64-none-elf?
Definition: BareMetal.cpp:129
clang::driver::Multilib::flag
Multilib & flag(StringRef F)
Add a flag to the flags list Flag must be a flag accepted by the driver with its leading '-' removed,...
Definition: Multilib.h:92
clang::driver::Compilation
Compilation - A set of tasks to perform for a single driver invocation.
Definition: Compilation.h:45
clang::driver::toolchains::BareMetal::AddCXXStdlibLibArgs
void AddCXXStdlibLibArgs(const llvm::opt::ArgList &Args, llvm::opt::ArgStringList &CmdArgs) const override
AddCXXStdlibLibArgs - Add the system specific linker arguments to use for the given C++ standard libr...
Definition: BareMetal.cpp:266
clang::driver::ToolChain::GetCXXStdlibType
virtual CXXStdlibType GetCXXStdlibType(const llvm::opt::ArgList &Args) const
Definition: ToolChain.cpp:893
clang::driver::toolchains::Generic_GCC::GCCVersion::Major
int Major
The parsed major, minor, and patch numbers.
Definition: Gnu.h:166
clang::driver::InputInfo::getFilename
const char * getFilename() const
Definition: InputInfo.h:83
CommonArgs.h
clang
Definition: CalledOnceCheck.h:17
clang::driver::Driver
Driver - Encapsulate logic for constructing compilation processes from a set of gcc-driver-like comma...
Definition: Driver.h:75
clang::driver::tools::addMultilibFlag
void addMultilibFlag(bool Enabled, const char *const Flag, Multilib::flags_list &Flags)
Flag must be a flag accepted by the driver with its leading '-' removed,
Definition: CommonArgs.cpp:1734
clang::driver::ToolChain::Multilibs
MultilibSet Multilibs
Definition: ToolChain.h:189
clang::driver::DetectedMultilibs
Definition: Gnu.h:21
clang::driver::Driver::getVFS
llvm::vfs::FileSystem & getVFS() const
Definition: Driver.h:369
clang::driver::tools::riscv::getRISCVABI
StringRef getRISCVABI(const llvm::opt::ArgList &Args, const llvm::Triple &Triple)
clang::driver::toolchains::BareMetal::computeSysRoot
std::string computeSysRoot() const override
Return the sysroot, possibly searching for a default sysroot using target-specific logic.
Definition: BareMetal.cpp:175
isARMBareMetal
static bool isARMBareMetal(const llvm::Triple &Triple)
Is the triple {arm,thumb}-none-none-{eabi,eabihf} ?
Definition: BareMetal.cpp:110
clang::driver::Action::OffloadKind
OffloadKind
Definition: Action.h:86
clang::driver::toolchains::BareMetal::addClangTargetOptions
void addClangTargetOptions(const llvm::opt::ArgList &DriverArgs, llvm::opt::ArgStringList &CC1Args, Action::OffloadKind DeviceOffloadKind) const override
Add options that need to be passed to cc1 for this target.
Definition: BareMetal.cpp:207
clang::driver
Definition: Action.h:31
clang::driver::ResponseFileSupport::None
static constexpr ResponseFileSupport None()
Returns a ResponseFileSupport indicating that response files are not supported.
Definition: Job.h:78
clang::driver::ToolChain::addSystemInclude
static void addSystemInclude(const llvm::opt::ArgList &DriverArgs, llvm::opt::ArgStringList &CC1Args, const Twine &Path)
Utility function to add a system include directory to CC1 arguments.
Definition: ToolChain.cpp:919
clang::driver::toolchains::BareMetal::handlesTarget
static bool handlesTarget(const llvm::Triple &Triple)
Definition: BareMetal.cpp:166
clang::driver::JobAction
Definition: Action.h:398
clang::driver::toolchains::BareMetal::AddLinkRuntimeLib
void AddLinkRuntimeLib(const llvm::opt::ArgList &Args, llvm::opt::ArgStringList &CmdArgs) const
Definition: BareMetal.cpp:283