@@ -31,6 +31,40 @@ using namespace clang::driver;
3131using namespace clang ::driver::tools;
3232using namespace clang ::driver::toolchains;
3333
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+
3468static bool findRISCVMultilibs (const Driver &D,
3569 const llvm::Triple &TargetTriple,
3670 const ArgList &Args, DetectedMultilibs &Result) {
@@ -95,7 +129,8 @@ static bool findRISCVMultilibs(const Driver &D,
95129 return false ;
96130}
97131
98- static std::string computeBaseSysRoot (const Driver &D, bool IncludeTriple) {
132+ static std::string computeClangRuntimesSysRoot (const Driver &D,
133+ bool IncludeTriple) {
99134 if (!D.SysRoot .empty ())
100135 return D.SysRoot ;
101136
@@ -108,56 +143,123 @@ static std::string computeBaseSysRoot(const Driver &D, bool IncludeTriple) {
108143 return std::string (SysRootDir);
109144}
110145
111- BareMetal::BareMetal (const Driver &D, const llvm::Triple &Triple,
112- const ArgList &Args)
113- : ToolChain(D, Triple, Args),
114- SysRoot(computeBaseSysRoot(D, /* IncludeTriple=*/ true )) {
115- getProgramPaths ().push_back (getDriver ().Dir );
116-
117- findMultilibs (D, Triple, Args);
118- SmallString<128 > SysRoot (computeSysRoot ());
119- if (!SysRoot.empty ()) {
120- for (const Multilib &M : getOrderedMultilibs ()) {
121- SmallString<128 > Dir (SysRoot);
122- llvm::sys::path::append (Dir, M.osSuffix (), " lib" );
123- getFilePaths ().push_back (std::string (Dir));
124- getLibraryPaths ().push_back (std::string (Dir));
125- }
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 (options::OPT_gcc_toolchain) ||
152+ Args.getLastArg (clang::driver::options::OPT_gcc_install_dir_EQ)) {
153+ GCCInstallation.init (Triple, Args);
154+ return GCCInstallation.isValid ();
126155 }
156+ return false ;
127157}
128158
129- // / Is the triple {aarch64.aarch64_be}-none-elf?
130- static bool isAArch64BareMetal (const llvm::Triple &Triple) {
131- if (Triple.getArch () != llvm::Triple::aarch64 &&
132- Triple.getArch () != llvm::Triple::aarch64_be)
133- return false ;
134-
135- if (Triple.getVendor () != llvm::Triple::UnknownVendor)
136- return false ;
137-
138- if (Triple.getOS () != llvm::Triple::UnknownOS)
139- return false ;
140-
141- return Triple.getEnvironmentName () == " elf" ;
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 (GCCDir, D.Dir , " .." , D.getTargetTriple (),
166+ " lib/crt0.o" );
167+ return llvm::sys::fs::exists (GCCDir);
142168}
143169
144- static bool isRISCVBareMetal (const llvm::Triple &Triple) {
145- if (!Triple.isRISCV ())
146- return false ;
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 ;
147189
148- if (Triple.getVendor () != llvm::Triple::UnknownVendor)
149- return false ;
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 (inferredSysRoot, GCCInstallation.getParentLibPath (),
195+ " .." , 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 (inferredSysRoot, D.Dir , " .." , D.getTargetTriple ());
200+ }
201+ // If a valid sysroot was inferred and exists, use it
202+ if (!inferredSysRoot.empty () && llvm::sys::fs::exists (inferredSysRoot))
203+ return std::string (inferredSysRoot);
150204
151- if (Triple.getOS () != llvm::Triple::UnknownOS)
152- return false ;
205+ // Use the clang-runtimes path.
206+ return computeClangRuntimesSysRoot (D, /* IncludeTriple*/ true );
207+ }
153208
154- return Triple.getEnvironmentName () == " elf" ;
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, InstallPath + Path, Paths);
155216}
156217
157- // / Is the triple powerpc[64][le]-*-none-eabi?
158- static bool isPPCBareMetal (const llvm::Triple &Triple) {
159- return Triple.isPPC () && Triple.getOS () == llvm::Triple::UnknownOS &&
160- Triple.getEnvironment () == llvm::Triple::EABI;
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 (clang::diag::warn_drv_multilib_not_available_for_target);
230+
231+ Multilibs = GCCInstallation.getMultilibs ();
232+ SelectedMultilibs.assign ({GCCInstallation.getMultilib ()});
233+
234+ path_list &Paths = getFilePaths ();
235+ // Add toolchain/multilib specific file paths.
236+ addMultilibsFilePaths (D, Multilibs, SelectedMultilibs.back (),
237+ GCCInstallation.getInstallPath (), Paths);
238+ // Adding filepath for locating crt{begin,end}.o files.
239+ Paths.push_back (GCCInstallation.getInstallPath ().str ());
240+ // Adding filepath for locating crt0.o file.
241+ Paths.push_back (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 (Twine (GCCInstallation.getParentLibPath () + " /../" +
247+ GCCInstallation.getTriple ().str () + " /bin" )
248+ .str ());
249+ PPaths.push_back ((GCCInstallation.getParentLibPath () + " /../bin" ).str ());
250+ } else {
251+ getProgramPaths ().push_back (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 (Dir, M.osSuffix (), " lib" );
258+ getFilePaths ().push_back (std::string (Dir));
259+ getLibraryPaths ().push_back (std::string (Dir));
260+ }
261+ }
262+ }
161263}
162264
163265static void
@@ -216,7 +318,7 @@ getMultilibConfigPath(const Driver &D, const llvm::Triple &Triple,
216318 return {};
217319 }
218320 } else {
219- MultilibPath = computeBaseSysRoot (D, /* IncludeTriple=*/ false );
321+ MultilibPath = computeClangRuntimesSysRoot (D, /* IncludeTriple=*/ false );
220322 llvm::sys::path::append (MultilibPath, MultilibFilename);
221323 }
222324 return MultilibPath;
@@ -234,15 +336,15 @@ void BareMetal::findMultilibs(const Driver &D, const llvm::Triple &Triple,
234336 if (D.getVFS ().exists (*MultilibPath)) {
235337 // If multilib.yaml is found, update sysroot so it doesn't use a target
236338 // specific suffix
237- SysRoot = computeBaseSysRoot (D, /* IncludeTriple=*/ false );
339+ SysRoot = computeClangRuntimesSysRoot (D, /* IncludeTriple=*/ false );
238340 SmallVector<StringRef> CustomFlagMacroDefines;
239341 findMultilibsFromYAML (*this , D, *MultilibPath, Args, Result,
240342 CustomFlagMacroDefines);
241343 SelectedMultilibs = Result.SelectedMultilibs ;
242344 Multilibs = Result.Multilibs ;
243345 MultilibMacroDefines.append (CustomFlagMacroDefines.begin (),
244346 CustomFlagMacroDefines.end ());
245- } else if (isRISCVBareMetal (Triple)) {
347+ } else if (isRISCVBareMetal (Triple) && ! detectGCCToolchainAdjacent (D) ) {
246348 if (findRISCVMultilibs (D, Triple, Args, Result)) {
247349 SelectedMultilibs = Result.SelectedMultilibs ;
248350 Multilibs = Result.Multilibs ;
@@ -263,8 +365,6 @@ Tool *BareMetal::buildStaticLibTool() const {
263365 return new tools::baremetal::StaticLibTool (*this );
264366}
265367
266- std::string BareMetal::computeSysRoot () const { return SysRoot; }
267-
268368BareMetal::OrderedMultilibs BareMetal::getOrderedMultilibs () const {
269369 // Get multilibs in reverse order because they're ordered most-specific last.
270370 if (!SelectedMultilibs.empty ())
@@ -292,10 +392,10 @@ void BareMetal::AddClangSystemIncludeArgs(const ArgList &DriverArgs,
292392 if (std::optional<std::string> Path = getStdlibIncludePath ())
293393 addSystemInclude (DriverArgs, CC1Args, *Path);
294394
295- const SmallString<128 > SysRoot (computeSysRoot ());
296- if (!SysRoot .empty ()) {
395+ const SmallString<128 > SysRootDir (computeSysRoot ());
396+ if (!SysRootDir .empty ()) {
297397 for (const Multilib &M : getOrderedMultilibs ()) {
298- SmallString<128 > Dir (SysRoot );
398+ SmallString<128 > Dir (SysRootDir );
299399 llvm::sys::path::append (Dir, M.includeSuffix ());
300400 llvm::sys::path::append (Dir, " include" );
301401 addSystemInclude (DriverArgs, CC1Args, Dir.str ());
@@ -309,6 +409,19 @@ void BareMetal::addClangTargetOptions(const ArgList &DriverArgs,
309409 CC1Args.push_back (" -nostdsysteminc" );
310410}
311411
412+ void BareMetal::addLibStdCxxIncludePaths (
413+ const llvm::opt::ArgList &DriverArgs,
414+ llvm::opt::ArgStringList &CC1Args) const {
415+ if (!IsGCCInstallationValid)
416+ return ;
417+ const GCCVersion &Version = GCCInstallation.getVersion ();
418+ StringRef TripleStr = GCCInstallation.getTriple ().str ();
419+ const Multilib &Multilib = GCCInstallation.getMultilib ();
420+ addLibStdCXXIncludePaths (computeSysRoot () + " /include/c++/" + Version.Text ,
421+ TripleStr, Multilib.includeSuffix (), DriverArgs,
422+ CC1Args);
423+ }
424+
312425void BareMetal::AddClangCXXStdlibIncludeArgs (const ArgList &DriverArgs,
313426 ArgStringList &CC1Args) const {
314427 if (DriverArgs.hasArg (options::OPT_nostdinc, options::OPT_nostdlibinc,
@@ -339,23 +452,23 @@ void BareMetal::AddClangCXXStdlibIncludeArgs(const ArgList &DriverArgs,
339452 };
340453
341454 switch (GetCXXStdlibType (DriverArgs)) {
342- case ToolChain::CST_Libcxx: {
343- SmallString<128 > P (D.Dir );
344- llvm::sys::path::append (P, " .." , " include" );
345- AddCXXIncludePath (P);
346- break ;
347- }
348- case ToolChain::CST_Libstdcxx:
349- // We only support libc++ toolchain installation.
350- break ;
455+ case ToolChain::CST_Libcxx: {
456+ SmallString<128 > P (D.Dir );
457+ llvm::sys::path::append (P, " .." , " include" );
458+ AddCXXIncludePath (P);
459+ break ;
460+ }
461+ case ToolChain::CST_Libstdcxx:
462+ addLibStdCxxIncludePaths (DriverArgs, CC1Args);
463+ break ;
351464 }
352465
353- std::string SysRoot (computeSysRoot ());
354- if (SysRoot .empty ())
466+ std::string SysRootDir (computeSysRoot ());
467+ if (SysRootDir .empty ())
355468 return ;
356469
357470 for (const Multilib &M : getOrderedMultilibs ()) {
358- SmallString<128 > Dir (SysRoot );
471+ SmallString<128 > Dir (SysRootDir );
359472 llvm::sys::path::append (Dir, M.gccSuffix ());
360473 switch (GetCXXStdlibType (DriverArgs)) {
361474 case ToolChain::CST_Libcxx: {
0 commit comments