* [PATCH] rust: enable fully static linking with TCLIBC=musl
@ 2026-04-13 7:04 sunilkumar.dora
0 siblings, 0 replies; only message in thread
From: sunilkumar.dora @ 2026-04-13 7:04 UTC (permalink / raw)
To: openembedded-core; +Cc: SunilKumar.Dora, Sundeep.Kokkonda, Randy.MacLeod
From: Sunil Dora <sunilkumar.dora@windriver.com>
Fixes [YOCTO #16076]
Rust binaries built with TCLIBC=musl and
-C target-feature=+crt-static were still dynamically linked.
Fix this by addressing three issues:
1) Set crt-static-respected in the generated musl target spec
so rustc honors +crt-static. [1]
2) Add the target sysroot library path to the linker flags so
libunwind.a can be found.
3) Use LLVM libunwind for musl:
- GNU libunwind does not provide static libraries in OE
and lacks required _Unwind_* symbols on some architectures [2]
- libgcc_eh depends on pthread and cannot be used for fully
static linking with musl
- LLVM libunwind provides the required symbols without
additional dependencies
Install LLVM libunwind from libcxx and switch libstd-rs
to depend on libcxx for musl.
Also remove the obsolete DEPENDS:remove:riscv32/riscv64 = "libunwind"
lines added in 2021 when riscv musl support was still being patched.
LLVM libunwind supports both riscv32 and riscv64 - verified locally.
riscv32 support was upstreamed at [3].
Add a selftest to verify that produced binaries are statically linked.
[1] https://github.com/rust-lang/rust/blob/main/compiler/rustc_target/src/spec/mod.rs
[2] https://github.com/libunwind/libunwind/issues/761
[3] https://github.com/llvm/llvm-project/commit/b17d464
Reported-by: Nick Owens <nick.owens@eero.com>
Signed-off-by: Sunil Dora <sunilkumar.dora@windriver.com>
---
.../rust/rust-static-musl-test/Cargo.lock | 5 ++++
.../rust/rust-static-musl-test/Cargo.toml | 4 +++
.../rust/rust-static-musl-test/src/main.rs | 3 ++
.../rust/rust-static-musl-test_0.1.bb | 20 +++++++++++++
meta/classes-recipe/rust-common.bbclass | 1 +
.../classes-recipe/rust-target-config.bbclass | 2 ++
meta/lib/oeqa/selftest/cases/rust.py | 30 +++++++++++++++++++
meta/recipes-devtools/clang/libcxx_git.bb | 5 ++++
.../recipes-devtools/rust/libstd-rs_1.94.1.bb | 5 +---
9 files changed, 71 insertions(+), 4 deletions(-)
create mode 100644 meta-selftest/recipes-devtools/rust/rust-static-musl-test/Cargo.lock
create mode 100644 meta-selftest/recipes-devtools/rust/rust-static-musl-test/Cargo.toml
create mode 100644 meta-selftest/recipes-devtools/rust/rust-static-musl-test/src/main.rs
create mode 100644 meta-selftest/recipes-devtools/rust/rust-static-musl-test_0.1.bb
diff --git a/meta-selftest/recipes-devtools/rust/rust-static-musl-test/Cargo.lock b/meta-selftest/recipes-devtools/rust/rust-static-musl-test/Cargo.lock
new file mode 100644
index 0000000000..cb488024c3
--- /dev/null
+++ b/meta-selftest/recipes-devtools/rust/rust-static-musl-test/Cargo.lock
@@ -0,0 +1,5 @@
+version = 3
+
+[[package]]
+name = "rust-static-musl-test"
+version = "0.1.0"
diff --git a/meta-selftest/recipes-devtools/rust/rust-static-musl-test/Cargo.toml b/meta-selftest/recipes-devtools/rust/rust-static-musl-test/Cargo.toml
new file mode 100644
index 0000000000..d7071302bd
--- /dev/null
+++ b/meta-selftest/recipes-devtools/rust/rust-static-musl-test/Cargo.toml
@@ -0,0 +1,4 @@
+[package]
+name = "rust-static-musl-test"
+version = "0.1.0"
+edition = "2021"
diff --git a/meta-selftest/recipes-devtools/rust/rust-static-musl-test/src/main.rs b/meta-selftest/recipes-devtools/rust/rust-static-musl-test/src/main.rs
new file mode 100644
index 0000000000..85dcaf9df5
--- /dev/null
+++ b/meta-selftest/recipes-devtools/rust/rust-static-musl-test/src/main.rs
@@ -0,0 +1,3 @@
+fn main() {
+ println!("static-musl-ok");
+}
diff --git a/meta-selftest/recipes-devtools/rust/rust-static-musl-test_0.1.bb b/meta-selftest/recipes-devtools/rust/rust-static-musl-test_0.1.bb
new file mode 100644
index 0000000000..442c24c1da
--- /dev/null
+++ b/meta-selftest/recipes-devtools/rust/rust-static-musl-test_0.1.bb
@@ -0,0 +1,20 @@
+# SPDX-License-Identifier: MIT
+# Minimal Rust binary to test static musl linking (bug 16076)
+
+SUMMARY = "Minimal Rust binary for static musl linking regression test"
+LICENSE = "MIT"
+LIC_FILES_CHKSUM = "file://${COMMON_LICENSE_DIR}/MIT;md5=0835ade698e0bcf8506ecda2f7b4f302"
+
+SRC_URI = "file://Cargo.toml \
+ file://Cargo.lock \
+ file://src/main.rs \
+ "
+
+S = "${UNPACKDIR}"
+CARGO_SRC_DIR = ""
+
+inherit cargo
+
+COMPATIBLE_HOST = ".*-musl.*"
+
+SSTATE_SKIP_CREATION = "1"
diff --git a/meta/classes-recipe/rust-common.bbclass b/meta/classes-recipe/rust-common.bbclass
index 34bb2377cf..057aeda67a 100644
--- a/meta/classes-recipe/rust-common.bbclass
+++ b/meta/classes-recipe/rust-common.bbclass
@@ -161,6 +161,7 @@ WRAPPER_TARGET_CC = "${CC}"
WRAPPER_TARGET_CXX = "${CXX}"
WRAPPER_TARGET_CCLD = "${CCLD}"
WRAPPER_TARGET_LDFLAGS = "${LDFLAGS}"
+WRAPPER_TARGET_LDFLAGS:append:libc-musl = " -L${STAGING_DIR_TARGET}${libdir}"
WRAPPER_TARGET_EXTRALD = ""
# see recipes-devtools/gcc/gcc/0018-Add-ssp_nonshared-to-link-commandline-for-musl-targe.patch
# we need to link with ssp_nonshared on musl to avoid "undefined reference to `__stack_chk_fail_local'"
diff --git a/meta/classes-recipe/rust-target-config.bbclass b/meta/classes-recipe/rust-target-config.bbclass
index 2e83cf5aa7..3469de2142 100644
--- a/meta/classes-recipe/rust-target-config.bbclass
+++ b/meta/classes-recipe/rust-target-config.bbclass
@@ -429,6 +429,8 @@ def rust_gen_target(d, thing, wd, arch):
tspec['has-thread-local'] = True
tspec['position-independent-executables'] = True
tspec['panic-strategy'] = d.getVar("RUST_PANIC_STRATEGY")
+ if "musl" in tspec['llvm-target']:
+ tspec['crt-static-respected'] = True
# write out the target spec json file
with open(wd + rustsys + '.json', 'w') as f:
diff --git a/meta/lib/oeqa/selftest/cases/rust.py b/meta/lib/oeqa/selftest/cases/rust.py
index 7614941661..72ffa5f234 100644
--- a/meta/lib/oeqa/selftest/cases/rust.py
+++ b/meta/lib/oeqa/selftest/cases/rust.py
@@ -1,4 +1,5 @@
# SPDX-License-Identifier: MIT
+import os
import subprocess
import time
from oeqa.core.decorator import OETestTag
@@ -144,3 +145,32 @@ class RustSelfTestSystemEmulated(OESelftestTestCase, OEPTestResultTestCase):
test_results = parse_results(resultlog)
for test in test_results:
self.ptest_result(ptestsuite, test, test_results[test])
+
+# Regression test for bug 16076 - verify static linking with TCLIBC=musl
+class RustStaticMuslTest(OESelftestTestCase):
+
+ RECIPE = "rust-static-musl-test"
+
+ def setUp(self):
+ super().setUp()
+ self.write_config(
+ 'TCLIBC = "musl"\n'
+ 'RUSTFLAGS:append:pn-%s = " -C target-feature=+crt-static"\n' % self.RECIPE
+ )
+ result = bitbake(self.RECIPE, ignore_status=True)
+ self.assertEqual(result.status, 0,
+ msg="bitbake %s failed:\n%s" % (self.RECIPE, result.output))
+
+ def test_static_musl_linking(self):
+ workdir = get_bb_var("WORKDIR", self.RECIPE)
+ cargo_target_subdir = get_bb_var("CARGO_TARGET_SUBDIR", self.RECIPE)
+ pn = get_bb_var("PN", self.RECIPE)
+ binary = os.path.join(workdir, "build", "target",
+ cargo_target_subdir, pn)
+
+ result = runCmd("file %s" % binary, ignore_status=True)
+ self.assertIn("ELF", result.output,
+ msg="Not an ELF binary: %s" % result.output)
+ self.assertIn("statically linked", result.output,
+ msg="Binary is not statically linked. Regression of bug 16076.\n"
+ "file output: %s" % result.output)
diff --git a/meta/recipes-devtools/clang/libcxx_git.bb b/meta/recipes-devtools/clang/libcxx_git.bb
index 42b2c91e43..dff063ad8b 100644
--- a/meta/recipes-devtools/clang/libcxx_git.bb
+++ b/meta/recipes-devtools/clang/libcxx_git.bb
@@ -31,6 +31,11 @@ LIC_FILES_CHKSUM = "file://libcxx/LICENSE.TXT;md5=55d89dd7eec8d3b4204b680e27da39
OECMAKE_TARGET_COMPILE = "cxxabi cxx"
OECMAKE_TARGET_INSTALL = "install-cxxabi install-cxx"
+# LLVM libunwind.a needed for static Rust musl builds.
+# GNU libunwind never produces .a on musl so no collision risk.
+OECMAKE_TARGET_COMPILE:append:libc-musl = " unwind"
+OECMAKE_TARGET_INSTALL:append:libc-musl = " install-unwind"
+
CC = "${CCACHE}${HOST_PREFIX}clang ${HOST_CC_ARCH}${TOOLCHAIN_OPTIONS}"
CXX = "${CCACHE}${HOST_PREFIX}clang++ ${HOST_CC_ARCH}${TOOLCHAIN_OPTIONS}"
BUILD_CC = "${CCACHE}clang ${BUILD_CC_ARCH}"
diff --git a/meta/recipes-devtools/rust/libstd-rs_1.94.1.bb b/meta/recipes-devtools/rust/libstd-rs_1.94.1.bb
index 8af93bec57..2a5e977a5e 100644
--- a/meta/recipes-devtools/rust/libstd-rs_1.94.1.bb
+++ b/meta/recipes-devtools/rust/libstd-rs_1.94.1.bb
@@ -17,10 +17,7 @@ inherit cargo
CVE_PRODUCT = "rust"
-DEPENDS:append:libc-musl = " libunwind"
-# rv32 does not have libunwind ported yet
-DEPENDS:remove:riscv32 = "libunwind"
-DEPENDS:remove:riscv64 = "libunwind"
+DEPENDS:append:libc-musl = " libcxx"
# Embed bitcode in order to allow compiling both with and without LTO
RUSTFLAGS += "-Cembed-bitcode=yes"
--
2.49.0
^ permalink raw reply related [flat|nested] only message in thread
only message in thread, other threads:[~2026-04-13 7:05 UTC | newest]
Thread overview: (only message) (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2026-04-13 7:04 [PATCH] rust: enable fully static linking with TCLIBC=musl sunilkumar.dora
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox