1 //===-- BareMetal.cpp - Bare Metal ToolChain --------------------*- C++ -*-===//
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
7 //===----------------------------------------------------------------------===//
11 #include "CommonArgs.h"
13 #include "clang/Driver/InputInfo.h"
15 #include "Arch/RISCV.h"
16 #include "clang/Driver/Compilation.h"
17 #include "clang/Driver/Driver.h"
18 #include "clang/Driver/DriverDiagnostic.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"
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
;
31 static Multilib
makeMultilib(StringRef commonSuffix
) {
32 return Multilib(commonSuffix
, commonSuffix
, commonSuffix
);
35 static bool findRISCVMultilibs(const Driver
&D
,
36 const llvm::Triple
&TargetTriple
,
37 const ArgList
&Args
, DetectedMultilibs
&Result
) {
38 Multilib::flags_list Flags
;
39 StringRef Arch
= riscv::getRISCVArch(Args
, TargetTriple
);
40 StringRef Abi
= tools::riscv::getRISCVABI(Args
, TargetTriple
);
42 if (TargetTriple
.isRISCV64()) {
43 Multilib Imac
= makeMultilib("").flag("+march=rv64imac").flag("+mabi=lp64");
44 Multilib Imafdc
= makeMultilib("/rv64imafdc/lp64d")
45 .flag("+march=rv64imafdc")
50 (Arch
== "rv64imafdc") || (Arch
== "rv64gc"); // gc => imafdc
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
);
57 Result
.Multilibs
= MultilibSet().Either(Imac
, Imafdc
);
58 return Result
.Multilibs
.select(Flags
, Result
.SelectedMultilib
);
60 if (TargetTriple
.isRISCV32()) {
62 makeMultilib("").flag("+march=rv32imac").flag("+mabi=ilp32");
64 makeMultilib("/rv32i/ilp32").flag("+march=rv32i").flag("+mabi=ilp32");
66 makeMultilib("/rv32im/ilp32").flag("+march=rv32im").flag("+mabi=ilp32");
67 Multilib Iac
= makeMultilib("/rv32iac/ilp32")
68 .flag("+march=rv32iac")
70 Multilib Imafc
= makeMultilib("/rv32imafc/ilp32f")
71 .flag("+march=rv32imafc")
72 .flag("+mabi=ilp32f");
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
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
);
88 Result
.Multilibs
= MultilibSet().Either(I
, Im
, Iac
, Imac
, Imafc
);
89 return Result
.Multilibs
.select(Flags
, Result
.SelectedMultilib
);
94 BareMetal::BareMetal(const Driver
&D
, const llvm::Triple
&Triple
,
96 : ToolChain(D
, Triple
, Args
) {
97 getProgramPaths().push_back(getDriver().getInstalledDir());
98 if (getDriver().getInstalledDir() != getDriver().Dir
)
99 getProgramPaths().push_back(getDriver().Dir
);
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
));
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
)
115 if (Triple
.getVendor() != llvm::Triple::UnknownVendor
)
118 if (Triple
.getOS() != llvm::Triple::UnknownOS
)
121 if (Triple
.getEnvironment() != llvm::Triple::EABI
&&
122 Triple
.getEnvironment() != llvm::Triple::EABIHF
)
128 /// Is the triple aarch64-none-elf?
129 static bool isAArch64BareMetal(const llvm::Triple
&Triple
) {
130 if (Triple
.getArch() != llvm::Triple::aarch64
)
133 if (Triple
.getVendor() != llvm::Triple::UnknownVendor
)
136 if (Triple
.getOS() != llvm::Triple::UnknownOS
)
139 return Triple
.getEnvironmentName() == "elf";
142 static bool isRISCVBareMetal(const llvm::Triple
&Triple
) {
143 if (!Triple
.isRISCV())
146 if (Triple
.getVendor() != llvm::Triple::UnknownVendor
)
149 if (Triple
.getOS() != llvm::Triple::UnknownOS
)
152 return Triple
.getEnvironmentName() == "elf";
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
;
166 bool BareMetal::handlesTarget(const llvm::Triple
&Triple
) {
167 return isARMBareMetal(Triple
) || isAArch64BareMetal(Triple
) ||
168 isRISCVBareMetal(Triple
);
171 Tool
*BareMetal::buildLinker() const {
172 return new tools::baremetal::Linker(*this);
175 std::string
BareMetal::computeSysRoot() const {
176 if (!getDriver().SysRoot
.empty())
177 return getDriver().SysRoot
+ SelectedMultilib
.osSuffix();
179 SmallString
<128> SysRootDir
;
180 llvm::sys::path::append(SysRootDir
, getDriver().Dir
, "../lib/clang-runtimes",
181 getDriver().getTargetTriple());
183 SysRootDir
+= SelectedMultilib
.osSuffix();
184 return std::string(SysRootDir
);
187 void BareMetal::AddClangSystemIncludeArgs(const ArgList
&DriverArgs
,
188 ArgStringList
&CC1Args
) const {
189 if (DriverArgs
.hasArg(options::OPT_nostdinc
))
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());
198 if (!DriverArgs
.hasArg(options::OPT_nostdlibinc
)) {
199 SmallString
<128> Dir(computeSysRoot());
201 llvm::sys::path::append(Dir
, "include");
202 addSystemInclude(DriverArgs
, CC1Args
, Dir
.str());
207 void BareMetal::addClangTargetOptions(const ArgList
&DriverArgs
,
208 ArgStringList
&CC1Args
,
209 Action::OffloadKind
) const {
210 CC1Args
.push_back("-nostdsysteminc");
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
))
220 std::string
SysRoot(computeSysRoot());
224 switch (GetCXXStdlibType(DriverArgs
)) {
225 case ToolChain::CST_Libcxx
: {
226 SmallString
<128> Dir(SysRoot
);
227 llvm::sys::path::append(Dir
, "include", "c++", "v1");
228 addSystemInclude(DriverArgs
, CC1Args
, Dir
.str());
231 case ToolChain::CST_Libstdcxx
: {
232 SmallString
<128> Dir(SysRoot
);
233 llvm::sys::path::append(Dir
, "include", "c++");
235 Generic_GCC::GCCVersion Version
= {"", -1, -1, -1, "", "", ""};
236 // Walk the subdirs, and find the one with the newest gcc version:
237 for (llvm::vfs::directory_iterator
238 LI
= getDriver().getVFS().dir_begin(Dir
.str(), EC
),
240 !EC
&& LI
!= LE
; LI
= LI
.increment(EC
)) {
241 StringRef VersionText
= llvm::sys::path::filename(LI
->path());
242 auto CandidateVersion
= Generic_GCC::GCCVersion::Parse(VersionText
);
243 if (CandidateVersion
.Major
== -1)
245 if (CandidateVersion
<= Version
)
247 Version
= CandidateVersion
;
249 if (Version
.Major
== -1)
251 llvm::sys::path::append(Dir
, Version
.Text
);
252 addSystemInclude(DriverArgs
, CC1Args
, Dir
.str());
258 void BareMetal::AddCXXStdlibLibArgs(const ArgList
&Args
,
259 ArgStringList
&CmdArgs
) const {
260 switch (GetCXXStdlibType(Args
)) {
261 case ToolChain::CST_Libcxx
:
262 CmdArgs
.push_back("-lc++");
263 if (Args
.hasArg(options::OPT_fexperimental_library
))
264 CmdArgs
.push_back("-lc++experimental");
265 CmdArgs
.push_back("-lc++abi");
267 case ToolChain::CST_Libstdcxx
:
268 CmdArgs
.push_back("-lstdc++");
269 CmdArgs
.push_back("-lsupc++");
272 CmdArgs
.push_back("-lunwind");
275 void BareMetal::AddLinkRuntimeLib(const ArgList
&Args
,
276 ArgStringList
&CmdArgs
) const {
277 ToolChain::RuntimeLibType RLT
= GetRuntimeLibType(Args
);
279 case ToolChain::RLT_CompilerRT
: {
280 const std::string FileName
= getCompilerRT(Args
, "builtins");
281 llvm::StringRef BaseName
= llvm::sys::path::filename(FileName
);
282 BaseName
.consume_front("lib");
283 BaseName
.consume_back(".a");
284 CmdArgs
.push_back(Args
.MakeArgString("-l" + BaseName
));
287 case ToolChain::RLT_Libgcc
:
288 CmdArgs
.push_back("-lgcc");
291 llvm_unreachable("Unhandled RuntimeLibType.");
294 void baremetal::Linker::ConstructJob(Compilation
&C
, const JobAction
&JA
,
295 const InputInfo
&Output
,
296 const InputInfoList
&Inputs
,
298 const char *LinkingOutput
) const {
299 ArgStringList CmdArgs
;
301 auto &TC
= static_cast<const toolchains::BareMetal
&>(getToolChain());
303 AddLinkerInputs(TC
, Inputs
, Args
, CmdArgs
, JA
);
305 CmdArgs
.push_back("-Bstatic");
307 Args
.AddAllArgs(CmdArgs
, {options::OPT_L
, options::OPT_T_Group
,
308 options::OPT_e
, options::OPT_s
, options::OPT_t
,
309 options::OPT_Z_Flag
, options::OPT_r
});
311 TC
.AddFilePathLibArgs(Args
, CmdArgs
);
313 for (const auto &LibPath
: TC
.getLibraryPaths())
314 CmdArgs
.push_back(Args
.MakeArgString(llvm::Twine("-L", LibPath
)));
316 const std::string FileName
= TC
.getCompilerRT(Args
, "builtins");
317 llvm::SmallString
<128> PathBuf
{FileName
};
318 llvm::sys::path::remove_filename(PathBuf
);
319 CmdArgs
.push_back(Args
.MakeArgString("-L" + PathBuf
));
321 if (TC
.ShouldLinkCXXStdlib(Args
))
322 TC
.AddCXXStdlibLibArgs(Args
, CmdArgs
);
324 if (!Args
.hasArg(options::OPT_nostdlib
, options::OPT_nodefaultlibs
)) {
325 CmdArgs
.push_back("-lc");
326 CmdArgs
.push_back("-lm");
328 TC
.AddLinkRuntimeLib(Args
, CmdArgs
);
331 CmdArgs
.push_back("-o");
332 CmdArgs
.push_back(Output
.getFilename());
334 C
.addCommand(std::make_unique
<Command
>(JA
, *this, ResponseFileSupport::None(),
335 Args
.MakeArgString(TC
.GetLinkerPath()),
336 CmdArgs
, Inputs
, Output
));