@@ -33,6 +33,40 @@ using namespace clang::driver;
3333using namespace clang ::driver::tools;
3434using namespace clang ::driver::toolchains;
3535
36+ // / Is the triple {aarch64.aarch64_be}-none-elf?
37+ static bool isAArch64BareMetal (const llvm::Triple &Triple) {
38+ if (Triple.getArch () != llvm::Triple::aarch64 &&
39+ Triple.getArch () != llvm::Triple::aarch64_be)
40+ return false ;
41+
42+ if (Triple.getVendor () != llvm::Triple::UnknownVendor)
43+ return false ;
44+
45+ if (Triple.getOS () != llvm::Triple::UnknownOS)
46+ return false ;
47+
48+ return Triple.getEnvironmentName () == " elf" ;
49+ }
50+
51+ static bool isRISCVBareMetal (const llvm::Triple &Triple) {
52+ if (!Triple.isRISCV ())
53+ return false ;
54+
55+ if (Triple.getVendor () != llvm::Triple::UnknownVendor)
56+ return false ;
57+
58+ if (Triple.getOS () != llvm::Triple::UnknownOS)
59+ return false ;
60+
61+ return Triple.getEnvironmentName () == " elf" ;
62+ }
63+
64+ // / Is the triple powerpc[64][le]-*-none-eabi?
65+ static bool isPPCBareMetal (const llvm::Triple &Triple) {
66+ return Triple.isPPC () && Triple.getOS () == llvm::Triple::UnknownOS &&
67+ Triple.getEnvironment () == llvm::Triple::EABI;
68+ }
69+
3670static bool findRISCVMultilibs (const Driver &D,
3771 const llvm::Triple &TargetTriple,
3872 const ArgList &Args, DetectedMultilibs &Result) {
@@ -97,7 +131,8 @@ static bool findRISCVMultilibs(const Driver &D,
97131 return false ;
98132}
99133
100- static std::string computeBaseSysRoot (const Driver &D, bool IncludeTriple) {
134+ static std::string computeClangRuntimesSysRoot (const Driver &D,
135+ bool IncludeTriple) {
101136 if (!D.SysRoot .empty ())
102137 return D.SysRoot ;
103138
@@ -110,56 +145,113 @@ static std::string computeBaseSysRoot(const Driver &D, bool IncludeTriple) {
110145 return std::string (SysRootDir);
111146}
112147
113- BareMetal::BareMetal (const Driver &D, const llvm::Triple &Triple,
114- const ArgList &Args)
115- : ToolChain(D, Triple, Args),
116- SysRoot(computeBaseSysRoot(D, /* IncludeTriple=*/ true )) {
117- getProgramPaths ().push_back (getDriver ().Dir );
118-
119- findMultilibs (D, Triple, Args);
120- SmallString<128 > SysRoot (computeSysRoot ());
121- if (!SysRoot.empty ()) {
122- for (const Multilib &M : getOrderedMultilibs ()) {
123- SmallString<128 > Dir (SysRoot);
124- llvm::sys::path::append (Dir, M.osSuffix (), " lib" );
125- getFilePaths ().push_back (std::string (Dir));
126- getLibraryPaths ().push_back (std::string (Dir));
127- }
128- }
148+ // This logic is adapted from RISCVToolChain.cpp as part of the ongoing effort
149+ // to merge RISCVToolChain into the Baremetal toolchain. It infers the presence
150+ // of a valid GCC toolchain by checking whether the `crt0.o` file exists in the
151+ // `bin/../<target-triple>/lib` directory
152+ static bool detectGCCToolchainAdjacent (const Driver &D) {
153+ SmallString<128 > GCCDir;
154+ llvm::sys::path::append (GCCDir, D.Dir , " .." , D.getTargetTriple (),
155+ " lib/crt0.o" );
156+ return llvm::sys::fs::exists (GCCDir);
129157}
130158
131- // / Is the triple {aarch64.aarch64_be}-none-elf?
132- static bool isAArch64BareMetal (const llvm::Triple &Triple) {
133- if (Triple.getArch () != llvm::Triple::aarch64 &&
134- Triple.getArch () != llvm::Triple::aarch64_be)
135- return false ;
159+ // If no sysroot is provided the driver will first attempt to infer it from the
160+ // values of `--gcc-install-dir` or `--gcc-toolchain`, which specify the
161+ // location of a GCC toolchain.
162+ // If neither flag is used, the sysroot defaults to either:
163+ // - `bin/../<target-triple>`
164+ // - `bin/../lib/clang-runtimes/<target-triple>`
165+ //
166+ // To use the `clang-runtimes` path, ensure that `../<target-triple>/lib/crt0.o`
167+ // does not exist relative to the driver.
168+ std::string BareMetal::computeSysRoot () const {
169+ // Use Baremetal::sysroot if it has already been set.
170+ if (!SysRoot.empty ())
171+ return SysRoot;
172+
173+ // Use the sysroot specified via the `--sysroot` command-line flag, if
174+ // provided.
175+ const Driver &D = getDriver ();
176+ if (!D.SysRoot .empty ())
177+ return D.SysRoot ;
136178
137- if (Triple.getVendor () != llvm::Triple::UnknownVendor)
138- return false ;
179+ // Attempt to infer sysroot from a valid GCC installation.
180+ // If no valid GCC installation, check for a GCC toolchain alongside Clang.
181+ SmallString<128 > inferredSysRoot;
182+ if (GCCInstallation.isValid ()) {
183+ llvm::sys::path::append (inferredSysRoot, GCCInstallation.getParentLibPath (),
184+ " .." , GCCInstallation.getTriple ().str ());
185+ } else if (detectGCCToolchainAdjacent (D)) {
186+ // Use the triple as provided to the driver. Unlike the parsed triple
187+ // this has not been normalized to always contain every field.
188+ llvm::sys::path::append (inferredSysRoot, D.Dir , " .." , D.getTargetTriple ());
189+ }
139190
140- if (Triple.getOS () != llvm::Triple::UnknownOS)
141- return false ;
191+ // If a valid path was inferred and exists, use it
192+ if (!inferredSysRoot.empty () && llvm::sys::fs::exists (inferredSysRoot))
193+ return std::string (inferredSysRoot);
142194
143- return Triple.getEnvironmentName () == " elf" ;
195+ // Use the clang-runtimes path.
196+ return computeClangRuntimesSysRoot (D, /* IncludeTriple*/ true );
144197}
145198
146- static bool isRISCVBareMetal (const llvm::Triple &Triple) {
147- if (!Triple.isRISCV ())
148- return false ;
149-
150- if (Triple.getVendor () != llvm::Triple::UnknownVendor)
151- return false ;
152-
153- if (Triple.getOS () != llvm::Triple::UnknownOS)
154- return false ;
155-
156- return Triple.getEnvironmentName () == " elf" ;
199+ static void addMultilibsFilePaths (const Driver &D, const MultilibSet &Multilibs,
200+ const Multilib &Multilib,
201+ StringRef InstallPath,
202+ ToolChain::path_list &Paths) {
203+ if (const auto &PathsCallback = Multilibs.filePathsCallback ())
204+ for (const auto &Path : PathsCallback (Multilib))
205+ addPathIfExists (D, InstallPath + Path, Paths);
157206}
158207
159- // / Is the triple powerpc[64][le]-*-none-eabi?
160- static bool isPPCBareMetal (const llvm::Triple &Triple) {
161- return Triple.isPPC () && Triple.getOS () == llvm::Triple::UnknownOS &&
162- Triple.getEnvironment () == llvm::Triple::EABI;
208+ // GCC mutltilibs will only work for those targets that have their multlib
209+ // structure encoded into GCCInstallation. Baremetal toolchain supports ARM,
210+ // AArch64, RISCV and PPC and of these only RISCV have GCC multilibs hardcoded
211+ // in GCCInstallation.
212+ BareMetal::BareMetal (const Driver &D, const llvm::Triple &Triple,
213+ const ArgList &Args)
214+ : Generic_ELF(D, Triple, Args) {
215+ GCCInstallation.init (Triple, Args);
216+ // Call computeSysRoot to initialize Baremetal::Sysroot. The first call sets
217+ // and caches the value, and subsequent calls return the cached result.
218+ SysRoot = computeSysRoot ();
219+ if (GCCInstallation.isValid ()) {
220+ if (!isRISCVBareMetal (Triple))
221+ D.Diag (clang::diag::warn_drv_multilib_not_available_for_target);
222+
223+ Multilibs = GCCInstallation.getMultilibs ();
224+ SelectedMultilibs.assign ({GCCInstallation.getMultilib ()});
225+
226+ path_list &Paths = getFilePaths ();
227+ // Add toolchain/multilib specific file paths.
228+ addMultilibsFilePaths (D, Multilibs, SelectedMultilibs.back (),
229+ GCCInstallation.getInstallPath (), Paths);
230+ // Adding filepath for locating crt{begin,end}.o files.
231+ Paths.push_back (GCCInstallation.getInstallPath ().str ());
232+ // Adding filepath for locating crt0.o file.
233+ Paths.push_back (SysRoot + " /lib" );
234+
235+ ToolChain::path_list &PPaths = getProgramPaths ();
236+ // Multilib cross-compiler GCC installations put ld in a triple-prefixed
237+ // directory off of the parent of the GCC installation.
238+ PPaths.push_back (Twine (GCCInstallation.getParentLibPath () + " /../" +
239+ GCCInstallation.getTriple ().str () + " /bin" )
240+ .str ());
241+ PPaths.push_back ((GCCInstallation.getParentLibPath () + " /../bin" ).str ());
242+ } else {
243+ getProgramPaths ().push_back (getDriver ().Dir );
244+ findMultilibs (D, Triple, Args);
245+ const SmallString<128 > SysRootDir (SysRoot);
246+ if (!SysRootDir.empty ()) {
247+ for (const Multilib &M : getOrderedMultilibs ()) {
248+ SmallString<128 > Dir (SysRootDir);
249+ llvm::sys::path::append (Dir, M.osSuffix (), " lib" );
250+ getFilePaths ().push_back (std::string (Dir));
251+ getLibraryPaths ().push_back (std::string (Dir));
252+ }
253+ }
254+ }
163255}
164256
165257static void
@@ -218,7 +310,7 @@ getMultilibConfigPath(const Driver &D, const llvm::Triple &Triple,
218310 return {};
219311 }
220312 } else {
221- MultilibPath = computeBaseSysRoot (D, /* IncludeTriple=*/ false );
313+ MultilibPath = computeClangRuntimesSysRoot (D, /* IncludeTriple=*/ false );
222314 llvm::sys::path::append (MultilibPath, MultilibFilename);
223315 }
224316 return MultilibPath;
@@ -236,15 +328,15 @@ void BareMetal::findMultilibs(const Driver &D, const llvm::Triple &Triple,
236328 if (D.getVFS ().exists (*MultilibPath)) {
237329 // If multilib.yaml is found, update sysroot so it doesn't use a target
238330 // specific suffix
239- SysRoot = computeBaseSysRoot (D, /* IncludeTriple=*/ false );
331+ SysRoot = computeClangRuntimesSysRoot (D, /* IncludeTriple=*/ false );
240332 SmallVector<StringRef> CustomFlagMacroDefines;
241333 findMultilibsFromYAML (*this , D, *MultilibPath, Args, Result,
242334 CustomFlagMacroDefines);
243335 SelectedMultilibs = Result.SelectedMultilibs ;
244336 Multilibs = Result.Multilibs ;
245337 MultilibMacroDefines.append (CustomFlagMacroDefines.begin (),
246338 CustomFlagMacroDefines.end ());
247- } else if (isRISCVBareMetal (Triple)) {
339+ } else if (isRISCVBareMetal (Triple) && ! detectGCCToolchainAdjacent (D) ) {
248340 if (findRISCVMultilibs (D, Triple, Args, Result)) {
249341 SelectedMultilibs = Result.SelectedMultilibs ;
250342 Multilibs = Result.Multilibs ;
@@ -265,8 +357,6 @@ Tool *BareMetal::buildStaticLibTool() const {
265357 return new tools::baremetal::StaticLibTool (*this );
266358}
267359
268- std::string BareMetal::computeSysRoot () const { return SysRoot; }
269-
270360BareMetal::OrderedMultilibs BareMetal::getOrderedMultilibs () const {
271361 // Get multilibs in reverse order because they're ordered most-specific last.
272362 if (!SelectedMultilibs.empty ())
@@ -294,10 +384,10 @@ void BareMetal::AddClangSystemIncludeArgs(const ArgList &DriverArgs,
294384 if (std::optional<std::string> Path = getStdlibIncludePath ())
295385 addSystemInclude (DriverArgs, CC1Args, *Path);
296386
297- const SmallString<128 > SysRoot (computeSysRoot ());
298- if (!SysRoot .empty ()) {
387+ const SmallString<128 > SysRootDir (computeSysRoot ());
388+ if (!SysRootDir .empty ()) {
299389 for (const Multilib &M : getOrderedMultilibs ()) {
300- SmallString<128 > Dir (SysRoot );
390+ SmallString<128 > Dir (SysRootDir );
301391 llvm::sys::path::append (Dir, M.includeSuffix ());
302392 llvm::sys::path::append (Dir, " include" );
303393 addSystemInclude (DriverArgs, CC1Args, Dir.str ());
@@ -311,6 +401,19 @@ void BareMetal::addClangTargetOptions(const ArgList &DriverArgs,
311401 CC1Args.push_back (" -nostdsysteminc" );
312402}
313403
404+ void BareMetal::addLibStdCxxIncludePaths (
405+ const llvm::opt::ArgList &DriverArgs,
406+ llvm::opt::ArgStringList &CC1Args) const {
407+ if (!GCCInstallation.isValid ())
408+ return ;
409+ const GCCVersion &Version = GCCInstallation.getVersion ();
410+ StringRef TripleStr = GCCInstallation.getTriple ().str ();
411+ const Multilib &Multilib = GCCInstallation.getMultilib ();
412+ addLibStdCXXIncludePaths (computeSysRoot () + " /include/c++/" + Version.Text ,
413+ TripleStr, Multilib.includeSuffix (), DriverArgs,
414+ CC1Args);
415+ }
416+
314417void BareMetal::AddClangCXXStdlibIncludeArgs (const ArgList &DriverArgs,
315418 ArgStringList &CC1Args) const {
316419 if (DriverArgs.hasArg (options::OPT_nostdinc, options::OPT_nostdlibinc,
@@ -341,23 +444,23 @@ void BareMetal::AddClangCXXStdlibIncludeArgs(const ArgList &DriverArgs,
341444 };
342445
343446 switch (GetCXXStdlibType (DriverArgs)) {
344- case ToolChain::CST_Libcxx: {
345- SmallString<128 > P (D.Dir );
346- llvm::sys::path::append (P, " .." , " include" );
347- AddCXXIncludePath (P);
348- break ;
349- }
350- case ToolChain::CST_Libstdcxx:
351- // We only support libc++ toolchain installation.
352- break ;
447+ case ToolChain::CST_Libcxx: {
448+ SmallString<128 > P (D.Dir );
449+ llvm::sys::path::append (P, " .." , " include" );
450+ AddCXXIncludePath (P);
451+ break ;
452+ }
453+ case ToolChain::CST_Libstdcxx:
454+ addLibStdCxxIncludePaths (DriverArgs, CC1Args);
455+ break ;
353456 }
354457
355- std::string SysRoot (computeSysRoot ());
356- if (SysRoot .empty ())
458+ std::string SysRootDir (computeSysRoot ());
459+ if (SysRootDir .empty ())
357460 return ;
358461
359462 for (const Multilib &M : getOrderedMultilibs ()) {
360- SmallString<128 > Dir (SysRoot );
463+ SmallString<128 > Dir (SysRootDir );
361464 llvm::sys::path::append (Dir, M.gccSuffix ());
362465 switch (GetCXXStdlibType (DriverArgs)) {
363466 case ToolChain::CST_Libcxx: {
0 commit comments