[clang] [Driver] Add support for GCC installation detection in Baremetal toolchain (PR #121829)
Peter Smith via cfe-commits
cfe-commits at lists.llvm.org
Tue Jun 10 08:01:22 PDT 2025
================
@@ -110,56 +144,99 @@ static std::string computeBaseSysRoot(const Driver &D, bool IncludeTriple) {
return std::string(SysRootDir);
}
-BareMetal::BareMetal(const Driver &D, const llvm::Triple &Triple,
- const ArgList &Args)
- : ToolChain(D, Triple, Args),
- SysRoot(computeBaseSysRoot(D, /*IncludeTriple=*/true)) {
- getProgramPaths().push_back(getDriver().Dir);
-
- findMultilibs(D, Triple, Args);
- SmallString<128> SysRoot(computeSysRoot());
- if (!SysRoot.empty()) {
- for (const Multilib &M : getOrderedMultilibs()) {
- SmallString<128> Dir(SysRoot);
- llvm::sys::path::append(Dir, M.osSuffix(), "lib");
- getFilePaths().push_back(std::string(Dir));
- getLibraryPaths().push_back(std::string(Dir));
- }
- }
+static bool hasGCCToolChainAlongSideClang(const Driver &D) {
+ SmallString<128> GCCDir;
+ llvm::sys::path::append(GCCDir, D.Dir, "..", D.getTargetTriple(),
+ "lib/crt0.o");
+ return llvm::sys::fs::exists(GCCDir);
}
-/// Is the triple {aarch64.aarch64_be}-none-elf?
-static bool isAArch64BareMetal(const llvm::Triple &Triple) {
- if (Triple.getArch() != llvm::Triple::aarch64 &&
- Triple.getArch() != llvm::Triple::aarch64_be)
- return false;
+// Users can specify their GCC toolchain using `-gcc-install-dir` or
+// `--gcc-toolchain`. If no sysroot is explicitly provided, the driver will
+// attempt to infer it from the values of the above flags.
+//
+// If neither flag is used, the sysroot defaults to either:
+// - `bin/../<target-triple>`
+// - `bin/../lib/clang-runtimes/<target-triple>`
+//
+// To use the `clang-runtimes` path, ensure that `../<target-triple>/lib/crt0.o`
+// does not exist relative to the driver.
+std::string BareMetal::computeSysRoot() const {
+ if (!SysRoot.empty())
+ return SysRoot;
- if (Triple.getVendor() != llvm::Triple::UnknownVendor)
- return false;
+ const Driver &D = getDriver();
+ if (!D.SysRoot.empty())
+ return D.SysRoot;
- if (Triple.getOS() != llvm::Triple::UnknownOS)
- return false;
+ // Verify the GCC installation from -gcc-install-dir, --gcc-toolchain, or
+ // alongside clang. If valid, form the sysroot. Otherwise, check
+ // lib/clang-runtimes above the driver.
+ SmallString<128> SysRootDir;
+ if (GCCInstallation.isValid()) {
+ StringRef LibDir = GCCInstallation.getParentLibPath();
+ StringRef TripleStr = GCCInstallation.getTriple().str();
+ llvm::sys::path::append(SysRootDir, LibDir, "..", TripleStr);
+ } else if (hasGCCToolChainAlongSideClang(D)) {
+ // Use the triple as provided to the driver. Unlike the parsed triple
+ // this has not been normalized to always contain every field.
+ llvm::sys::path::append(SysRootDir, D.Dir, "..", D.getTargetTriple());
+ }
- return Triple.getEnvironmentName() == "elf";
+ if (llvm::sys::fs::exists(SysRootDir))
+ return std::string(SysRootDir);
+ return computeBaseSysRoot(D, /*IncludeTriple*/ true);
}
-static bool isRISCVBareMetal(const llvm::Triple &Triple) {
- if (!Triple.isRISCV())
- return false;
-
- if (Triple.getVendor() != llvm::Triple::UnknownVendor)
- return false;
-
- if (Triple.getOS() != llvm::Triple::UnknownOS)
- return false;
-
- return Triple.getEnvironmentName() == "elf";
+static void addMultilibsFilePaths(const Driver &D, const MultilibSet &Multilibs,
+ const Multilib &Multilib,
+ StringRef InstallPath,
+ ToolChain::path_list &Paths) {
+ if (const auto &PathsCallback = Multilibs.filePathsCallback())
+ for (const auto &Path : PathsCallback(Multilib))
+ addPathIfExists(D, InstallPath + Path, Paths);
}
-/// Is the triple powerpc[64][le]-*-none-eabi?
-static bool isPPCBareMetal(const llvm::Triple &Triple) {
- return Triple.isPPC() && Triple.getOS() == llvm::Triple::UnknownOS &&
- Triple.getEnvironment() == llvm::Triple::EABI;
+// GCC mutltilibs will only work for those targets that have their multlib
+// structure encoded into GCCInstallation. Baremetal toolchain support ARM,
+// AArch64, RISCV and PPC and of them only RISCV have GCC multilibs hardcoded
+// in GCCInstallation.
+BareMetal::BareMetal(const Driver &D, const llvm::Triple &Triple,
+ const ArgList &Args)
+ : Generic_ELF(D, Triple, Args) {
+ GCCInstallation.init(Triple, Args);
+ SysRoot = computeSysRoot();
----------------
smithp35 wrote:
I was referring to the code path that starts at the constructor `BareMetal::BareMetal` takes the else branch for `GCCInstallation.isValid()` and calls `findMultilibs()`
If there is a `multilib.yaml` file found then the BareMetal::SysRoot that was computed in the constructor is updated by
```
// If multilib.yaml is found, update sysroot so it doesn't use a target
// specific suffix
SysRoot = computeClangRuntimesSysRoot(D, /*IncludeTriple=*/false);
```
Subsequent calls to computeSysRoot() will return that updated value.
So we need to cache the `SysRoot in BareMetal::SysRoot`. From following through the code it looks like that calculation of the updated SysRoot doesn't call `computeSysRoot()` so it looks like it is possible to make SysRoot a local variable here (ideally changing its name). This will lose some performance as it looks like `computeSysRoot()` is called several times later in `addLibStdCxxIncludePaths()` and `AddClangCXXStdlibIncludeArgs()` and there's no other place that assigns to `SysRoot` but `findMultiLibs()` , but it could be done.
Hopefully that explains it. In summary we can make SysRoot a local variable here with no loss in functionality but IIUC we'll lose some performance, which is likely negligble.
https://github.com/llvm/llvm-project/pull/121829
More information about the cfe-commits
mailing list