@@ -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) {
@@ -110,56 +144,99 @@ static std::string computeBaseSysRoot(const Driver &D, bool IncludeTriple) {
110144 return std::string (SysRootDir);
111145}
112146
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- }
147+ static bool hasGCCToolChainAlongSideClang (const Driver &D) {
148+ SmallString<128 > GCCDir;
149+ llvm::sys::path::append (GCCDir, D.Dir , " .." , D.getTargetTriple (),
150+ " lib/crt0.o" );
151+ return llvm::sys::fs::exists (GCCDir);
129152}
130153
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 ;
154+ // Users can specify their GCC toolchain using `-gcc-install-dir` or
155+ // `--gcc-toolchain`. If no sysroot is explicitly provided, the driver will
156+ // attempt to infer it from the values of the above flags.
157+ //
158+ // If neither flag is used, the sysroot defaults to either:
159+ // - `bin/../<target-triple>`
160+ // - `bin/../lib/clang-runtimes/<target-triple>`
161+ //
162+ // To use the `clang-runtimes` path, ensure that `../<target-triple>/lib/crt0.o`
163+ // does not exist relative to the driver.
164+ std::string BareMetal::computeSysRoot () const {
165+ if (!SysRoot.empty ())
166+ return SysRoot;
136167
137- if (Triple.getVendor () != llvm::Triple::UnknownVendor)
138- return false ;
168+ const Driver &D = getDriver ();
169+ if (!D.SysRoot .empty ())
170+ return D.SysRoot ;
139171
140- if (Triple.getOS () != llvm::Triple::UnknownOS)
141- return false ;
172+ // Verify the GCC installation from -gcc-install-dir, --gcc-toolchain, or
173+ // alongside clang. If valid, form the sysroot. Otherwise, check
174+ // lib/clang-runtimes above the driver.
175+ SmallString<128 > SysRootDir;
176+ if (GCCInstallation.isValid ()) {
177+ StringRef LibDir = GCCInstallation.getParentLibPath ();
178+ StringRef TripleStr = GCCInstallation.getTriple ().str ();
179+ llvm::sys::path::append (SysRootDir, LibDir, " .." , TripleStr);
180+ } else if (hasGCCToolChainAlongSideClang (D)) {
181+ // Use the triple as provided to the driver. Unlike the parsed triple
182+ // this has not been normalized to always contain every field.
183+ llvm::sys::path::append (SysRootDir, D.Dir , " .." , D.getTargetTriple ());
184+ }
142185
143- return Triple.getEnvironmentName () == " elf" ;
186+ if (llvm::sys::fs::exists (SysRootDir))
187+ return std::string (SysRootDir);
188+ return computeBaseSysRoot (D, /* IncludeTriple*/ true );
144189}
145190
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" ;
191+ static void addMultilibsFilePaths (const Driver &D, const MultilibSet &Multilibs,
192+ const Multilib &Multilib,
193+ StringRef InstallPath,
194+ ToolChain::path_list &Paths) {
195+ if (const auto &PathsCallback = Multilibs.filePathsCallback ())
196+ for (const auto &Path : PathsCallback (Multilib))
197+ addPathIfExists (D, InstallPath + Path, Paths);
157198}
158199
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;
200+ // GCC mutltilibs will only work for those targets that have their multlib
201+ // structure encoded into GCCInstallation. Baremetal toolchain support ARM,
202+ // AArch64, RISCV and PPC and of them only RISCV have GCC multilibs hardcoded
203+ // in GCCInstallation.
204+ BareMetal::BareMetal (const Driver &D, const llvm::Triple &Triple,
205+ const ArgList &Args)
206+ : Generic_ELF(D, Triple, Args) {
207+ GCCInstallation.init (Triple, Args);
208+ SysRoot = computeSysRoot ();
209+ if (GCCInstallation.isValid ()) {
210+ if (!isRISCVBareMetal (Triple))
211+ D.Diag (clang::diag::warn_drv_multilib_not_available_for_target);
212+ Multilibs = GCCInstallation.getMultilibs ();
213+ SelectedMultilibs.assign ({GCCInstallation.getMultilib ()});
214+ path_list &Paths = getFilePaths ();
215+ // Add toolchain/multilib specific file paths.
216+ addMultilibsFilePaths (D, Multilibs, SelectedMultilibs.back (),
217+ GCCInstallation.getInstallPath (), Paths);
218+ getFilePaths ().push_back (GCCInstallation.getInstallPath ().str ());
219+ ToolChain::path_list &PPaths = getProgramPaths ();
220+ // Multilib cross-compiler GCC installations put ld in a triple-prefixed
221+ // directory off of the parent of the GCC installation.
222+ PPaths.push_back (Twine (GCCInstallation.getParentLibPath () + " /../" +
223+ GCCInstallation.getTriple ().str () + " /bin" )
224+ .str ());
225+ PPaths.push_back ((GCCInstallation.getParentLibPath () + " /../bin" ).str ());
226+ getFilePaths ().push_back (SysRoot + " /lib" );
227+ } else {
228+ getProgramPaths ().push_back (getDriver ().Dir );
229+ findMultilibs (D, Triple, Args);
230+ const SmallString<128 > SysRootDir (computeSysRoot ());
231+ if (!SysRootDir.empty ()) {
232+ for (const Multilib &M : getOrderedMultilibs ()) {
233+ SmallString<128 > Dir (SysRootDir);
234+ llvm::sys::path::append (Dir, M.osSuffix (), " lib" );
235+ getFilePaths ().push_back (std::string (Dir));
236+ getLibraryPaths ().push_back (std::string (Dir));
237+ }
238+ }
239+ }
163240}
164241
165242static void
@@ -244,7 +321,7 @@ void BareMetal::findMultilibs(const Driver &D, const llvm::Triple &Triple,
244321 Multilibs = Result.Multilibs ;
245322 MultilibMacroDefines.append (CustomFlagMacroDefines.begin (),
246323 CustomFlagMacroDefines.end ());
247- } else if (isRISCVBareMetal (Triple)) {
324+ } else if (isRISCVBareMetal (Triple) && ! hasGCCToolChainAlongSideClang (D) ) {
248325 if (findRISCVMultilibs (D, Triple, Args, Result)) {
249326 SelectedMultilibs = Result.SelectedMultilibs ;
250327 Multilibs = Result.Multilibs ;
@@ -265,8 +342,6 @@ Tool *BareMetal::buildStaticLibTool() const {
265342 return new tools::baremetal::StaticLibTool (*this );
266343}
267344
268- std::string BareMetal::computeSysRoot () const { return SysRoot; }
269-
270345BareMetal::OrderedMultilibs BareMetal::getOrderedMultilibs () const {
271346 // Get multilibs in reverse order because they're ordered most-specific last.
272347 if (!SelectedMultilibs.empty ())
@@ -294,10 +369,10 @@ void BareMetal::AddClangSystemIncludeArgs(const ArgList &DriverArgs,
294369 if (std::optional<std::string> Path = getStdlibIncludePath ())
295370 addSystemInclude (DriverArgs, CC1Args, *Path);
296371
297- const SmallString<128 > SysRoot (computeSysRoot ());
298- if (!SysRoot .empty ()) {
372+ const SmallString<128 > SysRootDir (computeSysRoot ());
373+ if (!SysRootDir .empty ()) {
299374 for (const Multilib &M : getOrderedMultilibs ()) {
300- SmallString<128 > Dir (SysRoot );
375+ SmallString<128 > Dir (SysRootDir );
301376 llvm::sys::path::append (Dir, M.includeSuffix ());
302377 llvm::sys::path::append (Dir, " include" );
303378 addSystemInclude (DriverArgs, CC1Args, Dir.str ());
@@ -311,6 +386,19 @@ void BareMetal::addClangTargetOptions(const ArgList &DriverArgs,
311386 CC1Args.push_back (" -nostdsysteminc" );
312387}
313388
389+ void BareMetal::addLibStdCxxIncludePaths (
390+ const llvm::opt::ArgList &DriverArgs,
391+ llvm::opt::ArgStringList &CC1Args) const {
392+ if (!GCCInstallation.isValid ())
393+ return ;
394+ const GCCVersion &Version = GCCInstallation.getVersion ();
395+ StringRef TripleStr = GCCInstallation.getTriple ().str ();
396+ const Multilib &Multilib = GCCInstallation.getMultilib ();
397+ addLibStdCXXIncludePaths (computeSysRoot () + " /include/c++/" + Version.Text ,
398+ TripleStr, Multilib.includeSuffix (), DriverArgs,
399+ CC1Args);
400+ }
401+
314402void BareMetal::AddClangCXXStdlibIncludeArgs (const ArgList &DriverArgs,
315403 ArgStringList &CC1Args) const {
316404 if (DriverArgs.hasArg (options::OPT_nostdinc, options::OPT_nostdlibinc,
@@ -341,23 +429,23 @@ void BareMetal::AddClangCXXStdlibIncludeArgs(const ArgList &DriverArgs,
341429 };
342430
343431 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 ;
432+ case ToolChain::CST_Libcxx: {
433+ SmallString<128 > P (D.Dir );
434+ llvm::sys::path::append (P, " .." , " include" );
435+ AddCXXIncludePath (P);
436+ break ;
437+ }
438+ case ToolChain::CST_Libstdcxx:
439+ addLibStdCxxIncludePaths (DriverArgs, CC1Args);
440+ break ;
353441 }
354442
355- std::string SysRoot (computeSysRoot ());
356- if (SysRoot .empty ())
443+ std::string SysRootDir (computeSysRoot ());
444+ if (SysRootDir .empty ())
357445 return ;
358446
359447 for (const Multilib &M : getOrderedMultilibs ()) {
360- SmallString<128 > Dir (SysRoot );
448+ SmallString<128 > Dir (SysRootDir );
361449 llvm::sys::path::append (Dir, M.gccSuffix ());
362450 switch (GetCXXStdlibType (DriverArgs)) {
363451 case ToolChain::CST_Libcxx: {
0 commit comments