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>
Signed-off-by: Mathieu Dubois-Briand <mathieu.dubois-briand@bootlin.com>
--- /dev/null
+version = 3
+
+[[package]]
+name = "rust-static-musl-test"
+version = "0.1.0"
--- /dev/null
+[package]
+name = "rust-static-musl-test"
+version = "0.1.0"
+edition = "2021"
--- /dev/null
+fn main() {
+ println!("static-musl-ok");
+}
--- /dev/null
+# 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"
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'"
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:
# SPDX-License-Identifier: MIT
+import os
import subprocess
import time
from oeqa.core.decorator import OETestTag
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)
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}"
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"