[clang] [clang]: baremetal `multilib.yaml` discovery (PR #227965)
Mythreya Kuricheti via cfe-commits
cfe-commits at lists.llvm.org
Tue Oct 20 23:57:45 PDT 2026
https://github.com/MythreyaK updated https://github.com/llvm/llvm-project/pull/227965
>From ea6ec604e122df7ae834f6664046cdd63403ad79 Mon Sep 17 00:00:00 2001
From: Mythreya Kuricheti <git at mythreya.dev>
Date: Thu, 1 Oct 2026 05:43:57 +0000
Subject: [PATCH 1/4] [clang]: baremetal `multilib.yaml` discovery
Clang does not auto-detect `multilib.yaml` in the triple dirs
correctly because baremetal targets use `SYSROOT` as a fallback
dir, unlike the linux `multilib.yaml` discovery, which correctly
searches the triple-specific dirs first (`FallbackDir` dir is
unset).
`findMultilibsYAML` treats `FallbackDir` and `getStdlibPath()`
as mutually-exclusive settings. Because baremetal uses a fallback
path `SYSROOT/multilib.yaml`, `getStdlibPath()` is never searched
(`SYSROOT/usr/lib/<triple>/multilib.yaml`).
With this change to shared `Toolchain.cpp`, baremetal targets
look for a `multilib.yaml` in the triple-specific dirs first,
before attempting to locate it in SYSROOT. Attempt triple-specific
dirs first if present, `FallbackDir` otherwise.
---
clang/lib/Driver/ToolChain.cpp | 6 +++---
1 file changed, 3 insertions(+), 3 deletions(-)
diff --git a/clang/lib/Driver/ToolChain.cpp b/clang/lib/Driver/ToolChain.cpp
index 255a9c9602b54..037e0b5477348 100644
--- a/clang/lib/Driver/ToolChain.cpp
+++ b/clang/lib/Driver/ToolChain.cpp
@@ -202,10 +202,10 @@ ToolChain::findMultilibsYAML(const llvm::opt::ArgList &Args, const Driver &D,
}
SmallString<128> MultilibPath;
- if (!FallbackDir.empty())
- MultilibPath = FallbackDir;
- else if (std::optional<std::string> StdlibDir = getStdlibPath())
+ if (std::optional<std::string> StdlibDir = getStdlibPath())
MultilibPath = *StdlibDir;
+ else if (!FallbackDir.empty())
+ MultilibPath = FallbackDir;
else
return std::nullopt;
llvm::sys::path::append(MultilibPath, "multilib.yaml");
>From c1007519ebb77271b6e41bad45eb62fb69e759b0 Mon Sep 17 00:00:00 2001
From: Mythreya Kuricheti <git at mythreya.dev>
Date: Thu, 1 Oct 2026 08:46:26 +0000
Subject: [PATCH 2/4] add lit test
---
.../baremetal-multilib-autodiscovery.yaml | 64 +++++++++++++++++++
1 file changed, 64 insertions(+)
create mode 100644 clang/test/Driver/baremetal-multilib-autodiscovery.yaml
diff --git a/clang/test/Driver/baremetal-multilib-autodiscovery.yaml b/clang/test/Driver/baremetal-multilib-autodiscovery.yaml
new file mode 100644
index 0000000000000..5472a3ef215d7
--- /dev/null
+++ b/clang/test/Driver/baremetal-multilib-autodiscovery.yaml
@@ -0,0 +1,64 @@
+# UNSUPPORTED: system-windows
+
+# Test that baremetal toolchain discovers multilib.yaml in per-triple dirs
+# when no sysroot-level multilib.yaml exists. This tests the fallthrough
+# from FallbackDir to getStdlibPath() in findMultilibsYAML.
+
+## Test 1: per-triple autodiscovery (no sysroot-level YAML)
+#
+# getStdlibPath() = D.Dir/../lib/<triple> = %t/a/sysroot/usr/lib/riscv64-unknown-none-elf
+# FallbackDir = D.SysRoot = %t/a/sysroot (no multilib.yaml here)
+#
+# RUN: mkdir -p %t/a/sysroot/usr/bin
+# RUN: mkdir -p %t/a/sysroot/usr/lib/riscv64-unknown-none-elf/rv64gc/lib
+# RUN: cp %s %t/a/sysroot/usr/lib/riscv64-unknown-none-elf/multilib.yaml
+# RUN: %clang -no-canonical-prefixes -print-multi-lib 2>&1 \
+# RUN: --target=riscv64-unknown-none-elf -march=rv64gc \
+# RUN: --sysroot=%t/a/sysroot \
+# RUN: -ccc-install-dir %t/a/sysroot/usr/bin \
+# RUN: | FileCheck --check-prefix=CHECK-FOUND %s
+# CHECK-FOUND: rv64gc/lib;@-target=riscv64-unknown-none-elf at mabi=lp64d at march=rv64i2p1_m2p0_a2p1_f2p2_d2p2_c2p0_zicsr2p0_zifencei2p0_zmmul1p0_zaamo1p0_zalrsc1p0_zca1p0_zcd1p0
+
+# RUN: %clang -no-canonical-prefixes -print-multi-directory 2>&1 \
+# RUN: --target=riscv64-unknown-none-elf -march=rv64gc \
+# RUN: --sysroot=%t/a/sysroot \
+# RUN: -ccc-install-dir %t/a/sysroot/usr/bin \
+# RUN: | FileCheck --check-prefix=CHECK-DIR %s
+# CHECK-DIR: rv64gc/lib
+
+## Test 2: sysroot-level YAML still works via FallbackDir
+#
+# Place YAML at sysroot root only, no per-triple YAML.
+#
+# RUN: mkdir -p %t/b/sysroot/usr/bin
+# RUN: cp %s %t/b/sysroot/multilib.yaml
+# RUN: %clang -no-canonical-prefixes -print-multi-lib 2>&1 \
+# RUN: --target=riscv64-unknown-none-elf -march=rv64gc \
+# RUN: --sysroot=%t/b/sysroot \
+# RUN: -ccc-install-dir %t/b/sysroot/usr/bin \
+# RUN: | FileCheck --check-prefix=CHECK-SYSROOT %s
+# CHECK-SYSROOT: rv64gc/lib;@-target=riscv64-unknown-none-elf at mabi=lp64d at march=rv64i2p1_m2p0_a2p1_f2p2_d2p2_c2p0_zicsr2p0_zifencei2p0_zmmul1p0_zaamo1p0_zalrsc1p0_zca1p0_zcd1p0
+
+## Test 3: per-triple takes priority over sysroot-level
+#
+# Both exist: per-triple has real YAML, sysroot root has empty YAML.
+# getStdlibPath() is tried before FallbackDir, so per-triple wins.
+#
+# RUN: mkdir -p %t/c/sysroot/usr/bin
+# RUN: mkdir -p %t/c/sysroot/usr/lib/riscv64-unknown-none-elf/rv64gc/lib
+# RUN: cp %s %t/c/sysroot/usr/lib/riscv64-unknown-none-elf/multilib.yaml
+# RUN: cp %S/Inputs/multilib/empty.yaml %t/c/sysroot/multilib.yaml
+# RUN: %clang -no-canonical-prefixes -print-multi-lib 2>&1 \
+# RUN: --target=riscv64-unknown-none-elf -march=rv64gc \
+# RUN: --sysroot=%t/c/sysroot \
+# RUN: -ccc-install-dir %t/c/sysroot/usr/bin \
+# RUN: | FileCheck --check-prefix=CHECK-PRIORITY %s
+# CHECK-PRIORITY: rv64gc/lib;@-target=riscv64-unknown-none-elf at mabi=lp64d at march=rv64i2p1_m2p0_a2p1_f2p2_d2p2_c2p0_zicsr2p0_zifencei2p0_zmmul1p0_zaamo1p0_zalrsc1p0_zca1p0_zcd1p0
+
+---
+MultilibVersion: 1.0
+
+Variants:
+- Dir: rv64gc/lib
+ Flags: [--target=riscv64-unknown-none-elf, -mabi=lp64d,
+ -march=rv64i2p1_m2p0_a2p1_f2p2_d2p2_c2p0_zicsr2p0_zifencei2p0_zmmul1p0_zaamo1p0_zalrsc1p0_zca1p0_zcd1p0]
>From 766dfab7e90ce011f96c3cd179ef95c21bc17100 Mon Sep 17 00:00:00 2001
From: Mythreya Kuricheti <git at mythreya.dev>
Date: Sat, 10 Oct 2026 01:41:05 -0700
Subject: [PATCH 3/4] code review
- Ensure that `multilib.yaml` existing exists before committing to it
- Add a test for the case that @vhscampos caught during review
---
clang/lib/Driver/ToolChain.cpp | 30 ++++++++++++-------
.../baremetal-multilib-autodiscovery.yaml | 30 ++++++++++++++-----
2 files changed, 42 insertions(+), 18 deletions(-)
diff --git a/clang/lib/Driver/ToolChain.cpp b/clang/lib/Driver/ToolChain.cpp
index 037e0b5477348..84724440cb812 100644
--- a/clang/lib/Driver/ToolChain.cpp
+++ b/clang/lib/Driver/ToolChain.cpp
@@ -52,6 +52,7 @@
#include <cassert>
#include <cstddef>
#include <cstring>
+#include <optional>
#include <string>
using namespace clang;
@@ -201,17 +202,24 @@ ToolChain::findMultilibsYAML(const llvm::opt::ArgList &Args, const Driver &D,
return std::string(MultilibPath);
}
- SmallString<128> MultilibPath;
- if (std::optional<std::string> StdlibDir = getStdlibPath())
- MultilibPath = *StdlibDir;
- else if (!FallbackDir.empty())
- MultilibPath = FallbackDir;
- else
- return std::nullopt;
- llvm::sys::path::append(MultilibPath, "multilib.yaml");
- if (!D.getVFS().exists(MultilibPath))
- return std::nullopt;
- return std::string(MultilibPath);
+ const auto getMultilibYaml =
+ [&](StringRef Dir) -> std::optional<std::string> {
+ SmallString<128> MultilibPath(Dir);
+ llvm::sys::path::append(MultilibPath, "multilib.yaml");
+ if (!D.getVFS().exists(MultilibPath))
+ return std::nullopt;
+ return std::string(MultilibPath);
+ };
+
+ if (const auto StdlibDir = getStdlibPath()) {
+ if (auto MultilibYaml = getMultilibYaml(*StdlibDir))
+ return *MultilibYaml;
+ }
+
+ if (auto MultilibYaml = getMultilibYaml(FallbackDir))
+ return *MultilibYaml;
+
+ return std::nullopt;
}
void ToolChain::setTripleEnvironment(llvm::Triple::EnvironmentType Env) {
diff --git a/clang/test/Driver/baremetal-multilib-autodiscovery.yaml b/clang/test/Driver/baremetal-multilib-autodiscovery.yaml
index 5472a3ef215d7..f0ffe7af69cfc 100644
--- a/clang/test/Driver/baremetal-multilib-autodiscovery.yaml
+++ b/clang/test/Driver/baremetal-multilib-autodiscovery.yaml
@@ -2,9 +2,9 @@
# Test that baremetal toolchain discovers multilib.yaml in per-triple dirs
# when no sysroot-level multilib.yaml exists. This tests the fallthrough
-# from FallbackDir to getStdlibPath() in findMultilibsYAML.
+# from getStdlibPath() to FallbackDir in findMultilibsYAML.
-## Test 1: per-triple autodiscovery (no sysroot-level YAML)
+## Test 1: per-triple autodiscovery (no sysroot-level yaml)
#
# getStdlibPath() = D.Dir/../lib/<triple> = %t/a/sysroot/usr/lib/riscv64-unknown-none-elf
# FallbackDir = D.SysRoot = %t/a/sysroot (no multilib.yaml here)
@@ -26,9 +26,9 @@
# RUN: | FileCheck --check-prefix=CHECK-DIR %s
# CHECK-DIR: rv64gc/lib
-## Test 2: sysroot-level YAML still works via FallbackDir
+## Test 2: sysroot-level yaml still works via FallbackDir
#
-# Place YAML at sysroot root only, no per-triple YAML.
+# Place yaml at sysroot root only, no per-triple yaml.
#
# RUN: mkdir -p %t/b/sysroot/usr/bin
# RUN: cp %s %t/b/sysroot/multilib.yaml
@@ -39,10 +39,26 @@
# RUN: | FileCheck --check-prefix=CHECK-SYSROOT %s
# CHECK-SYSROOT: rv64gc/lib;@-target=riscv64-unknown-none-elf at mabi=lp64d at march=rv64i2p1_m2p0_a2p1_f2p2_d2p2_c2p0_zicsr2p0_zifencei2p0_zmmul1p0_zaamo1p0_zalrsc1p0_zca1p0_zcd1p0
-## Test 3: per-triple takes priority over sysroot-level
+## Test 3: fallthrough when getStdlibPath() dir exists but has no yaml
#
-# Both exist: per-triple has real YAML, sysroot root has empty YAML.
-# getStdlibPath() is tried before FallbackDir, so per-triple wins.
+# getStdlibPath() dir exists but contains no multilib.yaml.
+# Use sysroot-level yaml must still be found via FallbackDir.
+#
+# RUN: mkdir -p %t/d/sysroot/usr/bin
+# RUN: mkdir -p %t/d/sysroot/usr/lib/riscv64-unknown-none-elf
+# RUN: cp %s %t/d/sysroot/multilib.yaml
+# RUN: mkdir -p %t/d/sysroot/rv64gc/lib
+# RUN: %clang -no-canonical-prefixes -print-multi-lib 2>&1 \
+# RUN: --target=riscv64-unknown-none-elf -march=rv64gc \
+# RUN: --sysroot=%t/d/sysroot \
+# RUN: -ccc-install-dir %t/d/sysroot/usr/bin \
+# RUN: | FileCheck --check-prefix=CHECK-FALLTHROUGH %s
+# CHECK-FALLTHROUGH: rv64gc/lib;@-target=riscv64-unknown-none-elf at mabi=lp64d at march=rv64i2p1_m2p0_a2p1_f2p2_d2p2_c2p0_zicsr2p0_zifencei2p0_zmmul1p0_zaamo1p0_zalrsc1p0_zca1p0_zcd1p0
+
+## Test 4: per-triple takes priority over sysroot-level
+#
+# Both exist: per-triple has real yaml, sysroot has empty yaml.
+# getStdlibPath() is tried before FallbackDir, so per-triple should be selected.
#
# RUN: mkdir -p %t/c/sysroot/usr/bin
# RUN: mkdir -p %t/c/sysroot/usr/lib/riscv64-unknown-none-elf/rv64gc/lib
>From 503041b60ecb0c29c8f5a6cee45e1e6c14aa6a29 Mon Sep 17 00:00:00 2001
From: Mythreya Kuricheti <git at mythreya.dev>
Date: Tue, 20 Oct 2026 23:53:14 -0700
Subject: [PATCH 4/4] code review
Empty sysroot dir resolves to cwd. Add test.
---
clang/lib/Driver/ToolChain.cpp | 2 ++
.../Driver/baremetal-multilib-autodiscovery.yaml | 12 ++++++++++++
2 files changed, 14 insertions(+)
diff --git a/clang/lib/Driver/ToolChain.cpp b/clang/lib/Driver/ToolChain.cpp
index 84724440cb812..05c1957ee67fc 100644
--- a/clang/lib/Driver/ToolChain.cpp
+++ b/clang/lib/Driver/ToolChain.cpp
@@ -204,6 +204,8 @@ ToolChain::findMultilibsYAML(const llvm::opt::ArgList &Args, const Driver &D,
const auto getMultilibYaml =
[&](StringRef Dir) -> std::optional<std::string> {
+ if (Dir.empty())
+ return std::nullopt;
SmallString<128> MultilibPath(Dir);
llvm::sys::path::append(MultilibPath, "multilib.yaml");
if (!D.getVFS().exists(MultilibPath))
diff --git a/clang/test/Driver/baremetal-multilib-autodiscovery.yaml b/clang/test/Driver/baremetal-multilib-autodiscovery.yaml
index f0ffe7af69cfc..9f224345eebd9 100644
--- a/clang/test/Driver/baremetal-multilib-autodiscovery.yaml
+++ b/clang/test/Driver/baremetal-multilib-autodiscovery.yaml
@@ -71,6 +71,18 @@
# RUN: | FileCheck --check-prefix=CHECK-PRIORITY %s
# CHECK-PRIORITY: rv64gc/lib;@-target=riscv64-unknown-none-elf at mabi=lp64d at march=rv64i2p1_m2p0_a2p1_f2p2_d2p2_c2p0_zicsr2p0_zifencei2p0_zmmul1p0_zaamo1p0_zalrsc1p0_zca1p0_zcd1p0
+## Test 5: an empty FallbackDir must not pick up multilib.yaml from the CWD
+#
+# The Linux toolchain passes no FallbackDir.
+#
+# RUN: mkdir -p %t/e/cwd %t/e/install/bin
+# RUN: cp %s %t/e/cwd/multilib.yaml
+# RUN: cd %t/e/cwd && %clang -no-canonical-prefixes -print-multi-lib 2>&1 \
+# RUN: --target=x86_64-unknown-linux-gnu --sysroot= \
+# RUN: -ccc-install-dir %t/e/install/bin \
+# RUN: | FileCheck --check-prefix=CHECK-CWD %s
+# CHECK-CWD-NOT: rv64gc
+
---
MultilibVersion: 1.0
More information about the cfe-commits
mailing list