[clang] [Driver] Teach Barmetal toolchain about GCC installation (PR #121829)
Garvit Gupta via cfe-commits
cfe-commits at lists.llvm.org
Mon May 26 20:54:43 PDT 2025
================
@@ -110,20 +110,81 @@ static std::string computeBaseSysRoot(const Driver &D, bool IncludeTriple) {
return std::string(SysRootDir);
}
+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);
+}
+
+std::string BareMetal::computeSysRoot() const {
+ if (!SysRoot.empty())
+ return SysRoot;
+
+ const Driver &D = getDriver();
+ if (!D.SysRoot.empty())
+ return D.SysRoot;
+
+ // 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());
+ }
+
+ if (llvm::sys::fs::exists(SysRootDir))
+ return std::string(SysRootDir);
+ return computeBaseSysRoot(D, /*IncludeTriple*/ true);
+}
+
+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);
+}
+
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));
+ : Generic_ELF(D, Triple, Args) {
+ GCCInstallation.init(Triple, Args);
+ SysRoot = computeSysRoot();
+ if (GCCInstallation.isValid()) {
+ Multilibs = GCCInstallation.getMultilibs();
+ SelectedMultilibs.assign({GCCInstallation.getMultilib()});
+ path_list &Paths = getFilePaths();
+ // Add toolchain/multilib specific file paths.
+ addMultilibsFilePaths(D, Multilibs, SelectedMultilibs.back(),
+ GCCInstallation.getInstallPath(), Paths);
+ getFilePaths().push_back(GCCInstallation.getInstallPath().str());
+ ToolChain::path_list &PPaths = getProgramPaths();
+ // Multilib cross-compiler GCC installations put ld in a triple-prefixed
+ // directory off of the parent of the GCC installation.
+ PPaths.push_back(Twine(GCCInstallation.getParentLibPath() + "/../" +
+ GCCInstallation.getTriple().str() + "/bin")
+ .str());
+ PPaths.push_back((GCCInstallation.getParentLibPath() + "/../bin").str());
+ getFilePaths().push_back(SysRoot + "/lib");
+ } else {
----------------
quic-garvgupt wrote:
> Stepping back a bit, there's a bit of the logic/use-case in computeSysRoot that I don't understand. When we find a GCC ToolChain alongside clang, I don't see any logic to validate it.
There is no code to validate it in the constructor. However, it's use was needed in the linker job (see `Linker::ConstructJob`). This was done to preserve the behavior of RISCVToolChain Object. I am not sure why it was decided there that the mere presence of `lib/crt0.o` file alongside clang in target triple prefixed directory will indicate a GCC toolchain, however in RISCVToolchain object, toolchain found along clang isn't considered a valid GCCInstallation and the same has been implemented here to preserve that behavior.
One needs to look at `hasGCCToolchain`, `computeSysRoot` and constructor in RISCVToolChain.cpp for the same
>Is the intention here to find a valid GCC installation equivalent to the -gcc-install-dir or --gcc-toolchain, or something else?
Yes it is trying to find a toolchain that is equivalent to `--gcc-toolchain`. The same is also mentioned in the comments for the function `hasGCCToolChain` in RISCVToolChain.cpp. You can also look at tests "clang/test/Driver/riscv64-toolchain-extra.c` and "clang/test/Driver/riscv32-toolchain-extra.c" to see how it works.
> The logic in this block is the same as if clang-runtimes with multilib.yaml were used. Is this intentional?
I am not sure if I understood your question completely. But yes, the logic is a bit similar but the directory for sysroot will be different. In the case when GCCInstallation isn't valid but there is a GCC toolchain adjacent, then the sysroot would be `bin/../<target-triple>/lib/crt0.o` whereas with clang-runtimes with multilib.yaml, it will be `bin/../lib/clang-runtimes/` (include triple is set to false, when multilib.yaml is found).
Apologies for the late reply. I was out for sometime in the last month and then I my commit access got revoked. Thanks for reviewing this patch and pls let me know if you have further questions/comments.
https://github.com/llvm/llvm-project/pull/121829
More information about the cfe-commits
mailing list