@@ -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,123 @@ 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- }
148+ // Only consider the GCC toolchain based on the values provided through the
149+ // `--gcc-toolchain` and `--gcc-install-dir` flags. The function below returns
150+ // whether the GCC toolchain was initialized successfully.
151+ bool BareMetal::initGCCInstallation (const llvm::Triple &Triple,
152+ const llvm::opt::ArgList &Args) {
153+ if (Args.getLastArg (options::OPT_gcc_toolchain) ||
154+ Args.getLastArg (clang::driver::options::OPT_gcc_install_dir_EQ)) {
155+ GCCInstallation.init (Triple, Args);
156+ return GCCInstallation.isValid ();
128157 }
158+ return false ;
129159}
130160
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 ;
136-
137- if (Triple.getVendor () != llvm::Triple::UnknownVendor)
138- return false ;
139-
140- if (Triple.getOS () != llvm::Triple::UnknownOS)
141- return false ;
142-
143- return Triple.getEnvironmentName () == " elf" ;
161+ // This logic is adapted from RISCVToolChain.cpp as part of the ongoing effort
162+ // to merge RISCVToolChain into the Baremetal toolchain. It infers the presence
163+ // of a valid GCC toolchain by checking whether the `crt0.o` file exists in the
164+ // `bin/../<target-triple>/lib` directory.
165+ static bool detectGCCToolchainAdjacent (const Driver &D) {
166+ SmallString<128 > GCCDir;
167+ llvm::sys::path::append (GCCDir, D.Dir , " .." , D.getTargetTriple (),
168+ " lib/crt0.o" );
169+ return llvm::sys::fs::exists (GCCDir);
144170}
145171
146- static bool isRISCVBareMetal (const llvm::Triple &Triple) {
147- if (!Triple.isRISCV ())
148- return false ;
172+ // If no sysroot is provided the driver will first attempt to infer it from the
173+ // values of `--gcc-install-dir` or `--gcc-toolchain`, which specify the
174+ // location of a GCC toolchain.
175+ // If neither flag is used, the sysroot defaults to either:
176+ // - `bin/../<target-triple>`
177+ // - `bin/../lib/clang-runtimes/<target-triple>`
178+ //
179+ // To use the `clang-runtimes` path, ensure that `../<target-triple>/lib/crt0.o`
180+ // does not exist relative to the driver.
181+ std::string BareMetal::computeSysRoot () const {
182+ // Use Baremetal::sysroot if it has already been set.
183+ if (!SysRoot.empty ())
184+ return SysRoot;
185+
186+ // Use the sysroot specified via the `--sysroot` command-line flag, if
187+ // provided.
188+ const Driver &D = getDriver ();
189+ if (!D.SysRoot .empty ())
190+ return D.SysRoot ;
149191
150- if (Triple.getVendor () != llvm::Triple::UnknownVendor)
151- return false ;
192+ // Attempt to infer sysroot from a valid GCC installation.
193+ // If no valid GCC installation, check for a GCC toolchain alongside Clang.
194+ SmallString<128 > inferredSysRoot;
195+ if (IsGCCInstallationValid) {
196+ llvm::sys::path::append (inferredSysRoot, GCCInstallation.getParentLibPath (),
197+ " .." , GCCInstallation.getTriple ().str ());
198+ } else if (detectGCCToolchainAdjacent (D)) {
199+ // Use the triple as provided to the driver. Unlike the parsed triple
200+ // this has not been normalized to always contain every field.
201+ llvm::sys::path::append (inferredSysRoot, D.Dir , " .." , D.getTargetTriple ());
202+ }
203+ // If a valid sysroot was inferred and exists, use it
204+ if (!inferredSysRoot.empty () && llvm::sys::fs::exists (inferredSysRoot))
205+ return std::string (inferredSysRoot);
152206
153- if (Triple.getOS () != llvm::Triple::UnknownOS)
154- return false ;
207+ // Use the clang-runtimes path.
208+ return computeClangRuntimesSysRoot (D, /* IncludeTriple*/ true );
209+ }
155210
156- return Triple.getEnvironmentName () == " elf" ;
211+ static void addMultilibsFilePaths (const Driver &D, const MultilibSet &Multilibs,
212+ const Multilib &Multilib,
213+ StringRef InstallPath,
214+ ToolChain::path_list &Paths) {
215+ if (const auto &PathsCallback = Multilibs.filePathsCallback ())
216+ for (const auto &Path : PathsCallback (Multilib))
217+ addPathIfExists (D, InstallPath + Path, Paths);
157218}
158219
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;
220+ // GCC mutltilibs will only work for those targets that have their multlib
221+ // structure encoded into GCCInstallation. Baremetal toolchain supports ARM,
222+ // AArch64, RISCV and PPC and of these only RISCV have GCC multilibs hardcoded
223+ // in GCCInstallation.
224+ BareMetal::BareMetal (const Driver &D, const llvm::Triple &Triple,
225+ const ArgList &Args)
226+ : Generic_ELF(D, Triple, Args) {
227+ IsGCCInstallationValid = initGCCInstallation (Triple, Args);
228+ std::string ComputedSysRoot = computeSysRoot ();
229+ if (IsGCCInstallationValid) {
230+ if (!isRISCVBareMetal (Triple))
231+ D.Diag (clang::diag::warn_drv_multilib_not_available_for_target);
232+
233+ Multilibs = GCCInstallation.getMultilibs ();
234+ SelectedMultilibs.assign ({GCCInstallation.getMultilib ()});
235+
236+ path_list &Paths = getFilePaths ();
237+ // Add toolchain/multilib specific file paths.
238+ addMultilibsFilePaths (D, Multilibs, SelectedMultilibs.back (),
239+ GCCInstallation.getInstallPath (), Paths);
240+ // Adding filepath for locating crt{begin,end}.o files.
241+ Paths.push_back (GCCInstallation.getInstallPath ().str ());
242+ // Adding filepath for locating crt0.o file.
243+ Paths.push_back (ComputedSysRoot + " /lib" );
244+
245+ ToolChain::path_list &PPaths = getProgramPaths ();
246+ // Multilib cross-compiler GCC installations put ld in a triple-prefixed
247+ // directory off of the parent of the GCC installation.
248+ PPaths.push_back (Twine (GCCInstallation.getParentLibPath () + " /../" +
249+ GCCInstallation.getTriple ().str () + " /bin" )
250+ .str ());
251+ PPaths.push_back ((GCCInstallation.getParentLibPath () + " /../bin" ).str ());
252+ } else {
253+ getProgramPaths ().push_back (getDriver ().Dir );
254+ findMultilibs (D, Triple, Args);
255+ const SmallString<128 > SysRootDir (computeSysRoot ());
256+ if (!SysRootDir.empty ()) {
257+ for (const Multilib &M : getOrderedMultilibs ()) {
258+ SmallString<128 > Dir (SysRootDir);
259+ llvm::sys::path::append (Dir, M.osSuffix (), " lib" );
260+ getFilePaths ().push_back (std::string (Dir));
261+ getLibraryPaths ().push_back (std::string (Dir));
262+ }
263+ }
264+ }
163265}
164266
165267static void
@@ -218,7 +320,7 @@ getMultilibConfigPath(const Driver &D, const llvm::Triple &Triple,
218320 return {};
219321 }
220322 } else {
221- MultilibPath = computeBaseSysRoot (D, /* IncludeTriple=*/ false );
323+ MultilibPath = computeClangRuntimesSysRoot (D, /* IncludeTriple=*/ false );
222324 llvm::sys::path::append (MultilibPath, MultilibFilename);
223325 }
224326 return MultilibPath;
@@ -236,15 +338,15 @@ void BareMetal::findMultilibs(const Driver &D, const llvm::Triple &Triple,
236338 if (D.getVFS ().exists (*MultilibPath)) {
237339 // If multilib.yaml is found, update sysroot so it doesn't use a target
238340 // specific suffix
239- SysRoot = computeBaseSysRoot (D, /* IncludeTriple=*/ false );
341+ SysRoot = computeClangRuntimesSysRoot (D, /* IncludeTriple=*/ false );
240342 SmallVector<StringRef> CustomFlagMacroDefines;
241343 findMultilibsFromYAML (*this , D, *MultilibPath, Args, Result,
242344 CustomFlagMacroDefines);
243345 SelectedMultilibs = Result.SelectedMultilibs ;
244346 Multilibs = Result.Multilibs ;
245347 MultilibMacroDefines.append (CustomFlagMacroDefines.begin (),
246348 CustomFlagMacroDefines.end ());
247- } else if (isRISCVBareMetal (Triple)) {
349+ } else if (isRISCVBareMetal (Triple) && ! detectGCCToolchainAdjacent (D) ) {
248350 if (findRISCVMultilibs (D, Triple, Args, Result)) {
249351 SelectedMultilibs = Result.SelectedMultilibs ;
250352 Multilibs = Result.Multilibs ;
@@ -265,8 +367,6 @@ Tool *BareMetal::buildStaticLibTool() const {
265367 return new tools::baremetal::StaticLibTool (*this );
266368}
267369
268- std::string BareMetal::computeSysRoot () const { return SysRoot; }
269-
270370BareMetal::OrderedMultilibs BareMetal::getOrderedMultilibs () const {
271371 // Get multilibs in reverse order because they're ordered most-specific last.
272372 if (!SelectedMultilibs.empty ())
@@ -294,10 +394,10 @@ void BareMetal::AddClangSystemIncludeArgs(const ArgList &DriverArgs,
294394 if (std::optional<std::string> Path = getStdlibIncludePath ())
295395 addSystemInclude (DriverArgs, CC1Args, *Path);
296396
297- const SmallString<128 > SysRoot (computeSysRoot ());
298- if (!SysRoot .empty ()) {
397+ const SmallString<128 > SysRootDir (computeSysRoot ());
398+ if (!SysRootDir .empty ()) {
299399 for (const Multilib &M : getOrderedMultilibs ()) {
300- SmallString<128 > Dir (SysRoot );
400+ SmallString<128 > Dir (SysRootDir );
301401 llvm::sys::path::append (Dir, M.includeSuffix ());
302402 llvm::sys::path::append (Dir, " include" );
303403 addSystemInclude (DriverArgs, CC1Args, Dir.str ());
@@ -311,6 +411,19 @@ void BareMetal::addClangTargetOptions(const ArgList &DriverArgs,
311411 CC1Args.push_back (" -nostdsysteminc" );
312412}
313413
414+ void BareMetal::addLibStdCxxIncludePaths (
415+ const llvm::opt::ArgList &DriverArgs,
416+ llvm::opt::ArgStringList &CC1Args) const {
417+ if (!IsGCCInstallationValid)
418+ return ;
419+ const GCCVersion &Version = GCCInstallation.getVersion ();
420+ StringRef TripleStr = GCCInstallation.getTriple ().str ();
421+ const Multilib &Multilib = GCCInstallation.getMultilib ();
422+ addLibStdCXXIncludePaths (computeSysRoot () + " /include/c++/" + Version.Text ,
423+ TripleStr, Multilib.includeSuffix (), DriverArgs,
424+ CC1Args);
425+ }
426+
314427void BareMetal::AddClangCXXStdlibIncludeArgs (const ArgList &DriverArgs,
315428 ArgStringList &CC1Args) const {
316429 if (DriverArgs.hasArg (options::OPT_nostdinc, options::OPT_nostdlibinc,
@@ -341,23 +454,23 @@ void BareMetal::AddClangCXXStdlibIncludeArgs(const ArgList &DriverArgs,
341454 };
342455
343456 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 ;
457+ case ToolChain::CST_Libcxx: {
458+ SmallString<128 > P (D.Dir );
459+ llvm::sys::path::append (P, " .." , " include" );
460+ AddCXXIncludePath (P);
461+ break ;
462+ }
463+ case ToolChain::CST_Libstdcxx:
464+ addLibStdCxxIncludePaths (DriverArgs, CC1Args);
465+ break ;
353466 }
354467
355- std::string SysRoot (computeSysRoot ());
356- if (SysRoot .empty ())
468+ std::string SysRootDir (computeSysRoot ());
469+ if (SysRootDir .empty ())
357470 return ;
358471
359472 for (const Multilib &M : getOrderedMultilibs ()) {
360- SmallString<128 > Dir (SysRoot );
473+ SmallString<128 > Dir (SysRootDir );
361474 llvm::sys::path::append (Dir, M.gccSuffix ());
362475 switch (GetCXXStdlibType (DriverArgs)) {
363476 case ToolChain::CST_Libcxx: {
0 commit comments