clang 22.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 "Gnu.h"
14
15#include "Arch/AArch64.h"
16#include "Arch/ARM.h"
17#include "Arch/RISCV.h"
19#include "clang/Driver/Driver.h"
22#include "llvm/ADT/StringExtras.h"
23#include "llvm/Option/ArgList.h"
24#include "llvm/Support/Path.h"
25#include "llvm/Support/VirtualFileSystem.h"
26
27#include <sstream>
28
29using namespace llvm::opt;
30using namespace clang;
31using namespace clang::driver;
32using namespace clang::driver::tools;
33using namespace clang::driver::toolchains;
34
35static bool isRISCVBareMetal(const llvm::Triple &Triple) {
36 if (!Triple.isRISCV())
37 return false;
38
39 if (Triple.getVendor() != llvm::Triple::UnknownVendor)
40 return false;
41
42 if (Triple.getOS() != llvm::Triple::UnknownOS)
43 return false;
44
45 return Triple.getEnvironmentName() == "elf";
46}
47
48/ Is the triple powerpc[64][le]-*-none-eabi?
49static bool isPPCBareMetal(const llvm::Triple &Triple) {
50 return Triple.isPPC() && Triple.getOS() == llvm::Triple::UnknownOS &&
51 Triple.getEnvironment() == llvm::Triple::EABI;
52}
53
54static bool findRISCVMultilibs(const Driver &D,
55 const llvm::Triple &TargetTriple,
56 const ArgList &Args, DetectedMultilibs &Result) {
58 std::string Arch = riscv::getRISCVArch(Args, TargetTriple);
59 StringRef Abi = tools::riscv::getRISCVABI(Args, TargetTriple);
60
61 if (TargetTriple.isRISCV64()) {
62 MultilibBuilder Imac =
63 MultilibBuilder().flag("-march=rv64imac").flag("-mabi=lp64");
64 MultilibBuilder Imafdc = MultilibBuilder("/rv64imafdc/lp64d")
65 .flag("-march=rv64imafdc")
66 .flag("-mabi=lp64d");
67
68 / Multilib reuse
69 bool UseImafdc =
70 (Arch == "rv64imafdc") || (Arch == "rv64gc"); / gc => imafdc
71
72 addMultilibFlag((Arch == "rv64imac"), "-march=rv64imac", Flags);
73 addMultilibFlag(UseImafdc, "-march=rv64imafdc", Flags);
74 addMultilibFlag(Abi == "lp64", "-mabi=lp64", Flags);
75 addMultilibFlag(Abi == "lp64d", "-mabi=lp64d", Flags);
76
77 Result.Multilibs =
79 return Result.Multilibs.select(D, Flags, Result.SelectedMultilibs);
80 }
81 if (TargetTriple.isRISCV32()) {
82 MultilibBuilder Imac =
83 MultilibBuilder().flag("-march=rv32imac").flag("-mabi=ilp32");
84 MultilibBuilder I = MultilibBuilder("/rv32i/ilp32")
85 .flag("-march=rv32i")
86 .flag("-mabi=ilp32");
87 MultilibBuilder Im = MultilibBuilder("/rv32im/ilp32")
88 .flag("-march=rv32im")
89 .flag("-mabi=ilp32");
90 MultilibBuilder Iac = MultilibBuilder("/rv32iac/ilp32")
91 .flag("-march=rv32iac")
92 .flag("-mabi=ilp32");
93 MultilibBuilder Imafc = MultilibBuilder("/rv32imafc/ilp32f")
94 .flag("-march=rv32imafc")
95 .flag("-mabi=ilp32f");
96
97 / Multilib reuse
98 bool UseI = (Arch == "rv32i") || (Arch == "rv32ic"); / ic => i
99 bool UseIm = (Arch == "rv32im") || (Arch == "rv32imc"); / imc => im
100 bool UseImafc = (Arch == "rv32imafc") || (Arch == "rv32imafdc") ||
101 (Arch == "rv32gc"); / imafdc,gc => imafc
102
103 addMultilibFlag(UseI, "-march=rv32i", Flags);
104 addMultilibFlag(UseIm, "-march=rv32im", Flags);
105 addMultilibFlag((Arch == "rv32iac"), "-march=rv32iac", Flags);
106 addMultilibFlag((Arch == "rv32imac"), "-march=rv32imac", Flags);
107 addMultilibFlag(UseImafc, "-march=rv32imafc", Flags);
108 addMultilibFlag(Abi == "ilp32", "-mabi=ilp32", Flags);
109 addMultilibFlag(Abi == "ilp32f", "-mabi=ilp32f", Flags);
110
111 Result.Multilibs =
112 MultilibSetBuilder().Either(I, Im, Iac, Imac, Imafc).makeMultilibSet();
113 return Result.Multilibs.select(D, Flags, Result.SelectedMultilibs);
114 }
115 return false;
116}
117
118static std::string computeClangRuntimesSysRoot(const Driver &D,
119 bool IncludeTriple) {
120 if (!D.SysRoot.empty())
121 return D.SysRoot;
122
123 SmallString<128> SysRootDir(D.Dir);
124 llvm::sys::path::append(SysRootDir, "..", "lib", "clang-runtimes");
125
126 if (IncludeTriple)
127 llvm::sys::path::append(SysRootDir, D.getTargetTriple());
128
129 return std::string(SysRootDir);
130}
131
132/ Only consider the GCC toolchain based on the values provided through the
133/ `--gcc-toolchain` and `--gcc-install-dir` flags. The function below returns
134/ whether the GCC toolchain was initialized successfully.
135bool BareMetal::initGCCInstallation(const llvm::Triple &Triple,
136 const llvm::opt::ArgList &Args) {
137 if (Args.getLastArg(options::OPT_gcc_toolchain) ||
138 Args.getLastArg(clang::options::OPT_gcc_install_dir_EQ)) {
139 GCCInstallation.init(Triple, Args);
140 return GCCInstallation.isValid();
141 }
142 return false;
143}
144
145/ This logic is adapted from RISCVToolChain.cpp as part of the ongoing effort
146/ to merge RISCVToolChain into the Baremetal toolchain. It infers the presence
147/ of a valid GCC toolchain by checking whether the `crt0.o` file exists in the
148/ `bin/../<target-triple>/lib` directory.
149static bool detectGCCToolchainAdjacent(const Driver &D) {
150 SmallString<128> GCCDir;
151 llvm::sys::path::append(GCCDir, D.Dir, "..", D.getTargetTriple(),
152 "lib/crt0.o");
153 return llvm::sys::fs::exists(GCCDir);
154}
155
156/ If no sysroot is provided the driver will first attempt to infer it from the
157/ values of `--gcc-install-dir` or `--gcc-toolchain`, which specify the
158/ location of a GCC toolchain.
159/ If neither flag is used, the sysroot defaults to either:
160/    - `bin/../<target-triple>`
161/    - `bin/../lib/clang-runtimes/<target-triple>`
162/
163/ To use the `clang-runtimes` path, ensure that `../<target-triple>/lib/crt0.o`
164/ does not exist relative to the driver.
165std::string BareMetal::computeSysRoot() const {
166 / Use Baremetal::sysroot if it has already been set.
167 if (!SysRoot.empty())
168 return SysRoot;
169
170 / Use the sysroot specified via the `--sysroot` command-line flag, if
171 / provided.
172 const Driver &D = getDriver();
173 if (!D.SysRoot.empty())
174 return D.SysRoot;
175
176 / Attempt to infer sysroot from a valid GCC installation.
177 / If no valid GCC installation, check for a GCC toolchain alongside Clang.
178 SmallString<128> inferredSysRoot;
179 if (IsGCCInstallationValid) {
180 llvm::sys::path::append(inferredSysRoot, GCCInstallation.getParentLibPath(),
181 "..", GCCInstallation.getTriple().str());
182 } else if (detectGCCToolchainAdjacent(D)) {
183 / Use the triple as provided to the driver. Unlike the parsed triple
184 / this has not been normalized to always contain every field.
185 llvm::sys::path::append(inferredSysRoot, D.Dir, "..", D.getTargetTriple());
186 }
187 / If a valid sysroot was inferred and exists, use it
188 if (!inferredSysRoot.empty() && llvm::sys::fs::exists(inferredSysRoot))
189 return std::string(inferredSysRoot);
190
191 / Use the clang-runtimes path.
192 return computeClangRuntimesSysRoot(D, /*IncludeTriple*/ true);
193}
194
195std::string BareMetal::getCompilerRTPath() const {
196 const Driver &D = getDriver();
197 if (IsGCCInstallationValid || detectGCCToolchainAdjacent(getDriver())) {
198 SmallString<128> Path(D.ResourceDir);
199 llvm::sys::path::append(Path, "lib");
200 return std::string(Path.str());
201 }
203}
204
205static void addMultilibsFilePaths(const Driver &D, const MultilibSet &Multilibs,
206 const Multilib &Multilib,
207 StringRef InstallPath,
208 ToolChain::path_list &Paths) {
209 if (const auto &PathsCallback = Multilibs.filePathsCallback())
210 for (const auto &Path : PathsCallback(Multilib))
211 addPathIfExists(D, InstallPath + Path, Paths);
212}
213
214/ GCC mutltilibs will only work for those targets that have their multlib
215/ structure encoded into GCCInstallation. Baremetal toolchain supports ARM,
216/ AArch64, RISCV and PPC and of these only RISCV have GCC multilibs hardcoded
217/ in GCCInstallation.
218BareMetal::BareMetal(const Driver &D, const llvm::Triple &Triple,
219 const ArgList &Args)
220 : Generic_ELF(D, Triple, Args) {
221 IsGCCInstallationValid = initGCCInstallation(Triple, Args);
222 std::string ComputedSysRoot = computeSysRoot();
223 if (IsGCCInstallationValid) {
224 if (!isRISCVBareMetal(Triple))
225 D.Diag(clang::diag::warn_drv_multilib_not_available_for_target);
226
227 Multilibs = GCCInstallation.getMultilibs();
228 SelectedMultilibs.assign({GCCInstallation.getMultilib()});
229
230 path_list &Paths = getFilePaths();
231 / Add toolchain/multilib specific file paths.
233 GCCInstallation.getInstallPath(), Paths);
234 / Adding filepath for locating crt{begin,end}.o files.
235 Paths.push_back(GCCInstallation.getInstallPath().str());
236 / Adding filepath for locating crt0.o file.
237 Paths.push_back(ComputedSysRoot + "/lib");
238
240 / Multilib cross-compiler GCC installations put ld in a triple-prefixed
241 / directory off of the parent of the GCC installation.
242 PPaths.push_back(Twine(GCCInstallation.getParentLibPath() + "/../" +
243 GCCInstallation.getTriple().str() + "/bin")
244 .str());
245 PPaths.push_back((GCCInstallation.getParentLibPath() + "/../bin").str());
246 } else {
247 getProgramPaths().push_back(getDriver().Dir);
248 findMultilibs(D, Triple, Args);
249 const SmallString<128> SysRootDir(computeSysRoot());
250 if (!SysRootDir.empty()) {
251 for (const Multilib &M : getOrderedMultilibs()) {
252 SmallString<128> Dir(SysRootDir);
253 llvm::sys::path::append(Dir, M.osSuffix(), "lib");
254 getFilePaths().push_back(std::string(Dir));
255 getLibraryPaths().push_back(std::string(Dir));
256 }
257 }
258 }
259}
260
261static void
263 StringRef MultilibPath, const ArgList &Args,
264 DetectedMultilibs &Result,
265 SmallVector<StringRef> &CustomFlagsMacroDefines) {
266 llvm::ErrorOr<std::unique_ptr<llvm::MemoryBuffer>> MB =
267 D.getVFS().getBufferForFile(MultilibPath);
268 if (!MB)
269 return;
270 Multilib::flags_list Flags = TC.getMultilibFlags(Args);
271 llvm::ErrorOr<MultilibSet> ErrorOrMultilibSet =
272 MultilibSet::parseYaml(*MB.get());
273 if (ErrorOrMultilibSet.getError())
274 return;
275 Result.Multilibs = ErrorOrMultilibSet.get();
276 if (Result.Multilibs.select(D, Flags, Result.SelectedMultilibs,
277 &CustomFlagsMacroDefines))
278 return;
279 D.Diag(clang::diag::warn_drv_missing_multilib) << llvm::join(Flags, " ");
280 std::stringstream ss;
281
282 / If multilib selection didn't complete successfully, report a list
283 / of all the configurations the user could have provided.
284 for (const Multilib &Multilib : Result.Multilibs)
285 if (!Multilib.isError())
286 ss << "\n" << llvm::join(Multilib.flags(), " ");
287 D.Diag(clang::diag::note_drv_available_multilibs) << ss.str();
288
289 / Now report any custom error messages requested by the YAML. We do
290 / this after displaying the list of available multilibs, because
291 / that list is probably large, and (in interactive use) risks
292 / scrolling the useful error message off the top of the user's
293 / terminal.
294 for (const Multilib &Multilib : Result.SelectedMultilibs)
295 if (Multilib.isError())
296 D.Diag(clang::diag::err_drv_multilib_custom_error)
298
299 / If there was an error, clear the SelectedMultilibs vector, in
300 / case it contains partial data.
301 Result.SelectedMultilibs.clear();
302}
303
304static constexpr llvm::StringLiteral MultilibFilename = "multilib.yaml";
305
306static std::optional<llvm::SmallString<128>>
307getMultilibConfigPath(const Driver &D, const llvm::Triple &Triple,
308 const ArgList &Args) {
309 llvm::SmallString<128> MultilibPath;
310 if (Arg *ConfigFileArg = Args.getLastArg(options::OPT_multi_lib_config)) {
311 MultilibPath = ConfigFileArg->getValue();
312 if (!D.getVFS().exists(MultilibPath)) {
313 D.Diag(clang::diag::err_drv_no_such_file) << MultilibPath.str();
314 return {};
315 }
316 } else {
317 MultilibPath = computeClangRuntimesSysRoot(D, /*IncludeTriple=*/false);
318 llvm::sys::path::append(MultilibPath, MultilibFilename);
319 }
320 return MultilibPath;
321}
322
323void BareMetal::findMultilibs(const Driver &D, const llvm::Triple &Triple,
324 const ArgList &Args) {
326 / Look for a multilib.yaml before trying target-specific hardwired logic.
327 / If it exists, always do what it specifies.
328 std::optional<llvm::SmallString<128>> MultilibPath =
329 getMultilibConfigPath(D, Triple, Args);
330 if (!MultilibPath)
331 return;
332 if (D.getVFS().exists(*MultilibPath)) {
333 / If multilib.yaml is found, update sysroot so it doesn't use a target
334 / specific suffix
335 SysRoot = computeClangRuntimesSysRoot(D, /*IncludeTriple=*/false);
336 SmallVector<StringRef> CustomFlagMacroDefines;
337 findMultilibsFromYAML(*this, D, *MultilibPath, Args, Result,
338 CustomFlagMacroDefines);
339 SelectedMultilibs = Result.SelectedMultilibs;
340 Multilibs = Result.Multilibs;
341 MultilibMacroDefines.append(CustomFlagMacroDefines.begin(),
342 CustomFlagMacroDefines.end());
343 } else if (isRISCVBareMetal(Triple) && !detectGCCToolchainAdjacent(D)) {
344 if (findRISCVMultilibs(D, Triple, Args, Result)) {
345 SelectedMultilibs = Result.SelectedMultilibs;
346 Multilibs = Result.Multilibs;
347 }
348 }
349}
350
351bool BareMetal::handlesTarget(const llvm::Triple &Triple) {
352 return arm::isARMEABIBareMetal(Triple) ||
354 isPPCBareMetal(Triple);
355}
356
358 return new tools::baremetal::Linker(*this);
359}
360
364
365BareMetal::OrderedMultilibs BareMetal::getOrderedMultilibs() const {
366 / Get multilibs in reverse order because they're ordered most-specific last.
367 if (!SelectedMultilibs.empty())
368 return llvm::reverse(SelectedMultilibs);
369
370 / No multilibs selected so return a single default multilib.
372 return llvm::reverse(Default);
373}
374
376 if (getTriple().isRISCV() && IsGCCInstallationValid)
379}
380
382 if (getTriple().isRISCV() && IsGCCInstallationValid)
385}
386
387/ TODO: Add a validity check for GCCInstallation.
388/ If valid, use `UNW_Libgcc`; otherwise, use `UNW_None`.
390BareMetal::GetUnwindLibType(const llvm::opt::ArgList &Args) const {
391 if (getTriple().isRISCV())
392 return ToolChain::UNW_None;
393
394 return ToolChain::GetUnwindLibType(Args);
395}
396
397void BareMetal::AddClangSystemIncludeArgs(const ArgList &DriverArgs,
398 ArgStringList &CC1Args) const {
399 if (DriverArgs.hasArg(options::OPT_nostdinc))
400 return;
401
402 if (!DriverArgs.hasArg(options::OPT_nobuiltininc)) {
403 SmallString<128> Dir(getDriver().ResourceDir);
404 llvm::sys::path::append(Dir, "include");
405 addSystemInclude(DriverArgs, CC1Args, Dir.str());
406 }
407
408 if (DriverArgs.hasArg(options::OPT_nostdlibinc))
409 return;
410
411 const Driver &D = getDriver();
412
413 if (std::optional<std::string> Path = getStdlibIncludePath())
414 addSystemInclude(DriverArgs, CC1Args, *Path);
415
416 const SmallString<128> SysRootDir(computeSysRoot());
417 if (!SysRootDir.empty()) {
418 for (const Multilib &M : getOrderedMultilibs()) {
419 SmallString<128> Dir(SysRootDir);
420 llvm::sys::path::append(Dir, M.includeSuffix());
421 llvm::sys::path::append(Dir, "include");
422 addSystemInclude(DriverArgs, CC1Args, Dir.str());
423 }
424 SmallString<128> Dir(SysRootDir);
425 llvm::sys::path::append(Dir, getTripleString());
426 if (D.getVFS().exists(Dir)) {
427 llvm::sys::path::append(Dir, "include");
428 addSystemInclude(DriverArgs, CC1Args, Dir.str());
429 }
430 }
431}
432
433void BareMetal::addClangTargetOptions(const ArgList &DriverArgs,
434 ArgStringList &CC1Args,
435 Action::OffloadKind) const {
436 CC1Args.push_back("-nostdsysteminc");
437}
438
440 const llvm::opt::ArgList &DriverArgs,
441 llvm::opt::ArgStringList &CC1Args) const {
442 if (!IsGCCInstallationValid)
443 return;
444 const GCCVersion &Version = GCCInstallation.getVersion();
445 StringRef TripleStr = GCCInstallation.getTriple().str();
446 const Multilib &Multilib = GCCInstallation.getMultilib();
447 addLibStdCXXIncludePaths(computeSysRoot() + "/include/c++/" + Version.Text,
448 TripleStr, Multilib.includeSuffix(), DriverArgs,
449 CC1Args);
450}
451
452void BareMetal::AddClangCXXStdlibIncludeArgs(const ArgList &DriverArgs,
453 ArgStringList &CC1Args) const {
454 if (DriverArgs.hasArg(options::OPT_nostdinc, options::OPT_nostdlibinc,
455 options::OPT_nostdincxx))
456 return;
457
458 const Driver &D = getDriver();
459 std::string Target = getTripleString();
460
461 auto AddCXXIncludePath = [&](StringRef Path) {
462 std::string Version = detectLibcxxVersion(Path);
463 if (Version.empty())
464 return;
465
466 {
467 / First the per-target include dir: include/<target>/c++/v1.
468 SmallString<128> TargetDir(Path);
469 llvm::sys::path::append(TargetDir, Target, "c++", Version);
470 addSystemInclude(DriverArgs, CC1Args, TargetDir);
471 }
472
473 {
474 / Then the generic dir: include/c++/v1.
475 SmallString<128> Dir(Path);
476 llvm::sys::path::append(Dir, "c++", Version);
477 addSystemInclude(DriverArgs, CC1Args, Dir);
478 }
479 };
480
481 switch (GetCXXStdlibType(DriverArgs)) {
483 SmallString<128> P(D.Dir);
484 llvm::sys::path::append(P, "..", "include");
485 AddCXXIncludePath(P);
486 break;
487 }
489 addLibStdCxxIncludePaths(DriverArgs, CC1Args);
490 break;
491 }
492
493 std::string SysRootDir(computeSysRoot());
494 if (SysRootDir.empty())
495 return;
496
497 for (const Multilib &M : getOrderedMultilibs()) {
498 SmallString<128> Dir(SysRootDir);
499 llvm::sys::path::append(Dir, M.gccSuffix());
500 switch (GetCXXStdlibType(DriverArgs)) {
502 / First check sysroot/usr/include/c++/v1 if it exists.
503 SmallString<128> TargetDir(Dir);
504 llvm::sys::path::append(TargetDir, "usr", "include", "c++", "v1");
505 if (D.getVFS().exists(TargetDir)) {
506 addSystemInclude(DriverArgs, CC1Args, TargetDir.str());
507 break;
508 }
509 / Add generic paths if nothing else succeeded so far.
510 llvm::sys::path::append(Dir, "include", "c++", "v1");
511 addSystemInclude(DriverArgs, CC1Args, Dir.str());
512 break;
513 }
515 llvm::sys::path::append(Dir, "include", "c++");
516 std::error_code EC;
517 Generic_GCC::GCCVersion Version = {"", -1, -1, -1, "", ""};
518 / Walk the subdirs, and find the one with the newest gcc version:
519 for (llvm::vfs::directory_iterator
520 LI = D.getVFS().dir_begin(Dir.str(), EC),
521 LE;
522 !EC && LI != LE; LI = LI.increment(EC)) {
523 StringRef VersionText = llvm::sys::path::filename(LI->path());
524 auto CandidateVersion = Generic_GCC::GCCVersion::Parse(VersionText);
525 if (CandidateVersion.Major == -1)
526 continue;
527 if (CandidateVersion <= Version)
528 continue;
529 Version = CandidateVersion;
530 }
531 if (Version.Major != -1) {
532 llvm::sys::path::append(Dir, Version.Text);
533 addSystemInclude(DriverArgs, CC1Args, Dir.str());
534 }
535 break;
536 }
537 }
538 }
539 switch (GetCXXStdlibType(DriverArgs)) {
541 SmallString<128> Dir(SysRootDir);
542 llvm::sys::path::append(Dir, Target, "include", "c++", "v1");
543 if (D.getVFS().exists(Dir))
544 addSystemInclude(DriverArgs, CC1Args, Dir.str());
545 break;
546 }
548 break;
549 }
550}
551
553 const InputInfo &Output,
554 const InputInfoList &Inputs,
555 const ArgList &Args,
556 const char *LinkingOutput) const {
557 const Driver &D = getToolChain().getDriver();
558
559 / Silence warning for "clang -g foo.o -o foo"
560 Args.ClaimAllArgs(options::OPT_g_Group);
561 / and "clang -emit-llvm foo.o -o foo"
562 Args.ClaimAllArgs(options::OPT_emit_llvm);
563 / and for "clang -w foo.o -o foo". Other warning options are already
564 / handled somewhere else.
565 Args.ClaimAllArgs(options::OPT_w);
566 / Silence warnings when linking C code with a C++ '-stdlib' argument.
567 Args.ClaimAllArgs(options::OPT_stdlib_EQ);
568
569 / ar tool command "llvm-ar <options> <output_file> <input_files>".
570 ArgStringList CmdArgs;
571 / Create and insert file members with a deterministic index.
572 CmdArgs.push_back("rcsD");
573 CmdArgs.push_back(Output.getFilename());
574
575 for (const auto &II : Inputs) {
576 if (II.isFilename()) {
577 CmdArgs.push_back(II.getFilename());
578 }
579 }
580
581 / Delete old output archive file if it already exists before generating a new
582 / archive file.
583 const char *OutputFileName = Output.getFilename();
584 if (Output.isFilename() && llvm::sys::fs::exists(OutputFileName)) {
585 if (std::error_code EC = llvm::sys::fs::remove(OutputFileName)) {
586 D.Diag(diag::err_drv_unable_to_remove_file) << EC.message();
587 return;
588 }
589 }
590
591 const char *Exec = Args.MakeArgString(getToolChain().GetStaticLibToolPath());
592 C.addCommand(std::make_unique<Command>(JA, *this,
594 Exec, CmdArgs, Inputs, Output));
595}
596
598 const InputInfo &Output,
599 const InputInfoList &Inputs,
600 const ArgList &Args,
601 const char *LinkingOutput) const {
602 ArgStringList CmdArgs;
603
604 auto &TC = static_cast<const toolchains::BareMetal &>(getToolChain());
605 const Driver &D = getToolChain().getDriver();
606 const llvm::Triple::ArchType Arch = TC.getArch();
607 const llvm::Triple &Triple = getToolChain().getEffectiveTriple();
608 const bool IsStaticPIE = getStaticPIE(Args, TC);
609
610 if (!D.SysRoot.empty())
611 CmdArgs.push_back(Args.MakeArgString("--sysroot=" + D.SysRoot));
612
613 CmdArgs.push_back("-Bstatic");
614 if (IsStaticPIE) {
615 CmdArgs.push_back("-pie");
616 CmdArgs.push_back("--no-dynamic-linker");
617 CmdArgs.push_back("-z");
618 CmdArgs.push_back("text");
619 }
620
621 if (const char *LDMOption = getLDMOption(TC.getTriple(), Args)) {
622 CmdArgs.push_back("-m");
623 CmdArgs.push_back(LDMOption);
624 } else {
625 D.Diag(diag::err_target_unknown_triple) << Triple.str();
626 return;
627 }
628
629 if (Triple.isRISCV()) {
630 CmdArgs.push_back("-X");
631 if (Args.hasArg(options::OPT_mno_relax))
632 CmdArgs.push_back("--no-relax");
633 }
634
635 if (Triple.isARM() || Triple.isThumb()) {
636 bool IsBigEndian = arm::isARMBigEndian(Triple, Args);
637 if (IsBigEndian)
638 arm::appendBE8LinkFlag(Args, CmdArgs, Triple);
639 CmdArgs.push_back(IsBigEndian ? "-EB" : "-EL");
640 } else if (Triple.isAArch64()) {
641 CmdArgs.push_back(Arch == llvm::Triple::aarch64_be ? "-EB" : "-EL");
642 }
643
644 bool NeedCRTs =
645 !Args.hasArg(options::OPT_nostdlib, options::OPT_nostartfiles);
646
647 const char *CRTBegin, *CRTEnd;
648 if (NeedCRTs) {
649 if (!Args.hasArg(options::OPT_r)) {
650 const char *crt = "crt0.o";
651 if (IsStaticPIE)
652 crt = "rcrt1.o";
653 CmdArgs.push_back(Args.MakeArgString(TC.GetFilePath(crt)));
654 }
655 if (TC.hasValidGCCInstallation() || detectGCCToolchainAdjacent(D)) {
656 auto RuntimeLib = TC.GetRuntimeLibType(Args);
657 switch (RuntimeLib) {
658 case (ToolChain::RLT_Libgcc): {
659 CRTBegin = IsStaticPIE ? "crtbeginS.o" : "crtbegin.o";
660 CRTEnd = IsStaticPIE ? "crtendS.o" : "crtend.o";
661 break;
662 }
664 CRTBegin =
665 TC.getCompilerRTArgString(Args, "crtbegin", ToolChain::FT_Object);
666 CRTEnd =
667 TC.getCompilerRTArgString(Args, "crtend", ToolChain::FT_Object);
668 break;
669 }
670 }
671 CmdArgs.push_back(Args.MakeArgString(TC.GetFilePath(CRTBegin)));
672 }
673 }
674
675 Args.addAllArgs(CmdArgs,
676 {options::OPT_L, options::OPT_u, options::OPT_T_Group,
677 options::OPT_s, options::OPT_t, options::OPT_r});
678
679 TC.AddFilePathLibArgs(Args, CmdArgs);
680
681 for (const auto &LibPath : TC.getLibraryPaths())
682 CmdArgs.push_back(Args.MakeArgString(llvm::Twine("-L", LibPath)));
683
684 if (D.isUsingLTO())
685 addLTOOptions(TC, Args, CmdArgs, Output, Inputs,
686 D.getLTOMode() == LTOK_Thin);
687
688 AddLinkerInputs(TC, Inputs, Args, CmdArgs, JA);
689
690 if (TC.ShouldLinkCXXStdlib(Args)) {
691 bool OnlyLibstdcxxStatic = Args.hasArg(options::OPT_static_libstdcxx) &&
692 !Args.hasArg(options::OPT_static);
693 if (OnlyLibstdcxxStatic)
694 CmdArgs.push_back("-Bstatic");
695 TC.AddCXXStdlibLibArgs(Args, CmdArgs);
696 if (OnlyLibstdcxxStatic)
697 CmdArgs.push_back("-Bdynamic");
698 CmdArgs.push_back("-lm");
699 }
700
701 if (!Args.hasArg(options::OPT_nostdlib, options::OPT_nodefaultlibs)) {
702 CmdArgs.push_back("--start-group");
703 AddRunTimeLibs(TC, D, CmdArgs, Args);
704 if (!Args.hasArg(options::OPT_nolibc))
705 CmdArgs.push_back("-lc");
706 if (TC.hasValidGCCInstallation() || detectGCCToolchainAdjacent(D))
707 CmdArgs.push_back("-lgloss");
708 CmdArgs.push_back("--end-group");
709 }
710
711 if ((TC.hasValidGCCInstallation() || detectGCCToolchainAdjacent(D)) &&
712 NeedCRTs)
713 CmdArgs.push_back(Args.MakeArgString(TC.GetFilePath(CRTEnd)));
714
715 / The R_ARM_TARGET2 relocation must be treated as R_ARM_REL32 on arm*-*-elf
716 / and arm*-*-eabi (the default is R_ARM_GOT_PREL, used on arm*-*-linux and
717 / arm*-*-*bsd).
718 if (arm::isARMEABIBareMetal(TC.getTriple()))
719 CmdArgs.push_back("--target2=rel");
720
721 CmdArgs.push_back("-o");
722 CmdArgs.push_back(Output.getFilename());
723
724 C.addCommand(std::make_unique<Command>(
726 Args.MakeArgString(TC.GetLinkerPath()), CmdArgs, Inputs, Output));
727}
728
729/ BareMetal toolchain allows all sanitizers where the compiler generates valid
730/ code, ignoring all runtime library support issues on the assumption that
731/ baremetal targets typically implement their own runtime support.
733 const bool IsX86_64 = getTriple().getArch() == llvm::Triple::x86_64;
734 const bool IsAArch64 = getTriple().getArch() == llvm::Triple::aarch64 ||
735 getTriple().getArch() == llvm::Triple::aarch64_be;
736 const bool IsRISCV64 = getTriple().getArch() == llvm::Triple::riscv64;
738 Res |= SanitizerKind::Address;
739 Res |= SanitizerKind::KernelAddress;
740 Res |= SanitizerKind::PointerCompare;
741 Res |= SanitizerKind::PointerSubtract;
742 Res |= SanitizerKind::Fuzzer;
743 Res |= SanitizerKind::FuzzerNoLink;
744 Res |= SanitizerKind::Vptr;
745 Res |= SanitizerKind::SafeStack;
746 Res |= SanitizerKind::Thread;
747 Res |= SanitizerKind::Scudo;
748 if (IsX86_64 || IsAArch64 || IsRISCV64) {
749 Res |= SanitizerKind::HWAddress;
750 Res |= SanitizerKind::KernelHWAddress;
751 }
752 return Res;
753}
754
756BareMetal::getMultilibMacroDefinesStr(llvm::opt::ArgList &Args) const {
757 return MultilibMacroDefines;
758}
static std::string computeClangRuntimesSysRoot(const Driver &D, bool IncludeTriple)
static bool isRISCVBareMetal(const llvm::Triple &Triple)
Definition BareMetal.cpp:35
static std::optional< llvm::SmallString< 128 > > getMultilibConfigPath(const Driver &D, const llvm::Triple &Triple, const ArgList &Args)
static constexpr llvm::StringLiteral MultilibFilename
static bool detectGCCToolchainAdjacent(const Driver &D)
static bool isPPCBareMetal(const llvm::Triple &Triple)
Is the triple powerpc[64][le]-*-none-eabi?
Definition BareMetal.cpp:49
static void findMultilibsFromYAML(const ToolChain &TC, const Driver &D, StringRef MultilibPath, const ArgList &Args, DetectedMultilibs &Result, SmallVector< StringRef > &CustomFlagsMacroDefines)
static bool findRISCVMultilibs(const Driver &D, const llvm::Triple &TargetTriple, const ArgList &Args, DetectedMultilibs &Result)
Definition BareMetal.cpp:54
static void addMultilibsFilePaths(const Driver &D, const MultilibSet &Multilibs, const Multilib &Multilib, StringRef InstallPath, ToolChain::path_list &Paths)
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:99
std::string SysRoot
sysroot, if present
Definition Driver.h:205
DiagnosticBuilder Diag(unsigned DiagID) const
Definition Driver.h:169
llvm::vfs::FileSystem & getVFS() const
Definition Driver.h:427
std::string Dir
The path the driver executable was in, as invoked from the command line.
Definition Driver.h:180
bool isUsingLTO() const
Returns true if we are performing any kind of LTO.
Definition Driver.h:747
std::string getTargetTriple() const
Definition Driver.h:444
LTOKind getLTOMode() const
Get the specific kind of LTO being performed.
Definition Driver.h:750
InputInfo - Wrapper for information about an input source.
Definition InputInfo.h:22
const char * getFilename() const
Definition InputInfo.h:83
bool isFilename() const
Definition InputInfo.h:75
This corresponds to a single GCC multilib, or a segment of one controlled by a command line flag.
MultilibBuilder & flag(StringRef Flag, bool Disallow=false)
Add a flag to the flags list Flag must be a flag accepted by the driver.
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.
See also MultilibSetBuilder for combining multilibs into a set.
Definition Multilib.h:129
static llvm::ErrorOr< MultilibSet > parseYaml(llvm::MemoryBufferRef, llvm::SourceMgr::DiagHandlerTy=nullptr, void *DiagHandlerCtxt=nullptr)
Definition Multilib.cpp:479
const IncludeDirsFunc & filePathsCallback() const
Definition Multilib.h:206
This corresponds to a single GCC Multilib, or a segment of one controlled by a command line flag.
Definition Multilib.h:35
const std::string & getErrorMessage() const
Definition Multilib.h:99
const flags_list & flags() const
Get the flags that indicate or contraindicate this multilib's use All elements begin with either '-' ...
Definition Multilib.h:82
std::vector< std::string > flags_list
Definition Multilib.h:37
const std::string & includeSuffix() const
Get the include directory suffix.
Definition Multilib.h:78
bool isError() const
Definition Multilib.h:97
ToolChain - Access to tools for a single platform.
Definition ToolChain.h:92
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.
path_list & getFilePaths()
Definition ToolChain.h:295
const Driver & getDriver() const
Definition ToolChain.h:253
virtual std::string detectLibcxxVersion(StringRef IncludePath) const
Multilib::flags_list getMultilibFlags(const llvm::opt::ArgList &) const
Get flags suitable for multilib selection, based on the provided clang command line arguments.
path_list & getProgramPaths()
Definition ToolChain.h:298
const llvm::Triple & getTriple() const
Definition ToolChain.h:255
virtual UnwindLibType GetUnwindLibType(const llvm::opt::ArgList &Args) const
virtual std::string getCompilerRTPath() const
std::optional< std::string > getStdlibIncludePath() const
std::string getTripleString() const
Definition ToolChain.h:278
virtual CXXStdlibType GetCXXStdlibType(const llvm::opt::ArgList &Args) const
llvm::SmallVector< Multilib > SelectedMultilibs
Definition ToolChain.h:200
path_list & getLibraryPaths()
Definition ToolChain.h:292
virtual SanitizerMask getSupportedSanitizers() const
Return sanitizers which are available in this toolchain.
SmallVector< std::string, 16 > path_list
Definition ToolChain.h:94
Tool - Information on a specific compilation tool.
Definition Tool.h:32
const ToolChain & getToolChain() const
Definition Tool.h:52
std::string computeSysRoot() const override
Return the sysroot, possibly searching for a default sysroot using target-specific logic.
void addLibStdCxxIncludePaths(const llvm::opt::ArgList &DriverArgs, llvm::opt::ArgStringList &CC1Args) const override
BareMetal(const Driver &D, const llvm::Triple &Triple, const llvm::opt::ArgList &Args)
SanitizerMask getSupportedSanitizers() const override
Return sanitizers which are available in this toolchain.
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...
static bool handlesTarget(const llvm::Triple &Triple)
UnwindLibType GetUnwindLibType(const llvm::opt::ArgList &Args) const override
void AddClangSystemIncludeArgs(const llvm::opt::ArgList &DriverArgs, llvm::opt::ArgStringList &CC1Args) const override
Add the clang cc1 arguments for system include paths.
std::string getCompilerRTPath() const override
SmallVector< std::string > getMultilibMacroDefinesStr(llvm::opt::ArgList &Args) const override
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.
Tool * buildStaticLibTool() const override
void findMultilibs(const Driver &D, const llvm::Triple &Triple, const llvm::opt::ArgList &Args)
CXXStdlibType GetDefaultCXXStdlibType() const override
RuntimeLibType GetDefaultRuntimeLibType() const override
GetDefaultRuntimeLibType - Get the default runtime library variant to use.
bool initGCCInstallation(const llvm::Triple &Triple, const llvm::opt::ArgList &Args)
Tool * buildLinker() const override
Generic_ELF(const Driver &D, const llvm::Triple &Triple, const llvm::opt::ArgList &Args)
Definition Gnu.h:439
GCCInstallationDetector GCCInstallation
Definition Gnu.h:357
bool addLibStdCXXIncludePaths(Twine IncludeDir, StringRef Triple, Twine IncludeSuffix, const llvm::opt::ArgList &DriverArgs, llvm::opt::ArgStringList &CC1Args, bool DetectDebian=false) const
Definition Gnu.cpp:3307
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,...
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,...
bool isAArch64BareMetal(const llvm::Triple &Triple)
Is the triple {aarch64.aarch64_be}-none-elf?
Definition AArch64.cpp:475
void appendBE8LinkFlag(const llvm::opt::ArgList &Args, llvm::opt::ArgStringList &CmdArgs, const llvm::Triple &Triple)
bool isARMEABIBareMetal(const llvm::Triple &Triple)
Is the triple {arm,armeb,thumb,thumbeb}-none-none-{eabi,eabihf} ?
Definition ARM.cpp:55
bool isARMBigEndian(const llvm::Triple &Triple, const llvm::opt::ArgList &Args)
std::string getRISCVArch(const llvm::opt::ArgList &Args, const llvm::Triple &Triple)
Definition RISCV.cpp:239
StringRef getRISCVABI(const llvm::opt::ArgList &Args, const llvm::Triple &Triple)
bool getStaticPIE(const llvm::opt::ArgList &Args, const ToolChain &TC)
void addLTOOptions(const ToolChain &ToolChain, const llvm::opt::ArgList &Args, llvm::opt::ArgStringList &CmdArgs, const InputInfo &Output, const InputInfoList &Inputs, bool IsThinLTO)
void addMultilibFlag(bool Enabled, const StringRef Flag, Multilib::flags_list &Flags)
Flag must be a flag accepted by the driver.
void AddRunTimeLibs(const ToolChain &TC, const Driver &D, llvm::opt::ArgStringList &CmdArgs, const llvm::opt::ArgList &Args)
void addPathIfExists(const Driver &D, const Twine &Path, ToolChain::path_list &Paths)
void AddLinkerInputs(const ToolChain &TC, const InputInfoList &Inputs, const llvm::opt::ArgList &Args, llvm::opt::ArgStringList &CmdArgs, const JobAction &JA)
const char * getLDMOption(const llvm::Triple &T, const llvm::opt::ArgList &Args)
SmallVector< InputInfo, 4 > InputInfoList
Definition Driver.h:50
The JSON file list parser is used to communicate input to InstallAPI.
@ Result
The result type of a method or function.
Definition TypeBase.h:905
static constexpr ResponseFileSupport AtFileCurCP()
Definition Job.h:92
Struct to store and manipulate GCC versions.
Definition Gnu.h:163
int Major
The parsed major, minor, and patch numbers.
Definition Gnu.h:168
std::string Text
The unparsed text of the version.
Definition Gnu.h:165
static GCCVersion Parse(StringRef VersionText)
Parse a GCCVersion object out of a string of text.
Definition Gnu.cpp:1985

Follow Lee on X/Twitter - Father, Husband, Serial builder creating AI, crypto, games & web tools. We are friends :) AI Will Come To Life!

Check out: eBank.nz (Art Generator) | Netwrck.com (AI Tools) | Text-Generator.io (AI API) | BitBank.nz (Crypto AI) | ReadingTime (Kids Reading) | RewordGame | BigMultiplayerChess | WebFiddle | How.nz | Helix AI Assistant