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