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