rust-lang / rust-lang/rust

rust-lld default on x86_64-unknown-linux-gnu produces binaries without RUNPATH on NixOS

Open
#162,781 15 comments 0 reactions 0 assignees View on GitHub

Nobody has claimed this yet.

A-linkage C-discussion O-NixOS
Dominant language
Rust
Stars
119k
Forks
16.1k
PR merge metrics
PR metrics pending

Description

Since 1.90 (#140525) rustc links x86_64-unknown-linux-gnu binaries with the self-contained rust-lld. On NixOS this silently changes the output of any crate that links a system shared library: the binary no longer gets a RUNPATH, and it fails to start.

Background

NixOS has no /usr/lib. The cc on PATH is a nixpkgs wrapper whose companion ld wrapper appends -rpath <dir> for each -L directory in /nix/store that provides a linked -l library (ld-wrapper.sh). That is how every binary linked there finds its libraries at run time.

rust-lld is not reached through that ld wrapper, so no RUNPATH is written. The cc wrapper still passes -dynamic-linker for the Nix store glibc, so the binary is not a "foreign" one either, and NixOS's nix-ld fallback does not apply. The result links cleanly and dies at startup.

Reproduction

NixOS 26.05, rustup stable rustc 1.95.0 (59807616e 2026-04-14), LLVM 22.1.2, nixpkgs gcc-wrapper-15.2.0 as cc. Outside any nix-shell, with PKG_CONFIG_PATH pointing at the store's openssl/zlib/sqlite .pc directories:

[dependencies]
openssl-sys = "=0.9.117"
libz-sys = { version = "=1.1.29", default-features = false, features = ["libc"] }
libsqlite3-sys = "=0.38.2"
fn main() {
    unsafe {
        openssl_sys::init();
        let v = std::ffi::CStr::from_ptr(openssl_sys::OpenSSL_version(0));
        let z = std::ffi::CStr::from_ptr(libz_sys::zlibVersion());
        let s = std::ffi::CStr::from_ptr(libsqlite3_sys::sqlite3_libversion());
        println!("openssl={v:?} zlib={z:?} sqlite={s:?}");
    }
}
cargo build
readelf -p .comment target/debug/app | grep Linker   # Linker: LLD 22.1.2
readelf -d target/debug/app | grep RUNPATH           # (nothing)
ldd target/debug/app                                 # libssl.so.3 => not found, libcrypto.so.3 => not found, libsqlite3.so => not found
./target/debug/app                                   # error while loading shared libraries: libsqlite3.so ... (exit 127)

The same build through the same cc, opting out of the self-contained linker:

RUSTFLAGS="-Clinker-features=-lld -Clink-self-contained=-linker" cargo build
readelf -d target/debug/app | grep RUNPATH   # [/nix/store/…-sqlite-3.51.2/lib:/nix/store/…-openssl-3.6.3/lib:…]
./target/debug/app                           # openssl="OpenSSL 3.6.3 …" zlib="1.3.2" sqlite="3.51.2"
Linker RUNPATH ldd not found Run
rust-lld (default) none 3 exit 127
GNU ld via the nixpkgs wrapper store library dirs 0 exit 0

The same happens with clang-sys (libclang.so.21.1: cannot open shared object file), and with tools that inspect the result: a Python wheel backend that runs ldd to bundle OpenSSL failed because ldd reported it missing.

What would help

Any one of these:

  • Document the NixOS interaction next to the lld default and its opt-out, since the failure shows up at run time rather than link time.
  • When cc is a nixpkgs wrapper (e.g. it has a nix-support/ directory beside it), don't pick the self-contained linker, or warn that RUNPATH handling is lost.
  • Provide a hook for linker-wrapper rpath semantics when rust-lld replaces the system ld.
Workarounds (verified)
  • -Clinker-features=-lld -Clink-self-contained=-linker restores the wrapper's behaviour.
  • Put -rpath <dir> in the cc wrapper's cc-ldflags, which the cc wrapper passes to whatever linker it calls, rust-lld included. That is what this machine does now: https://github.com/zackees/nixos/commit/91d74c1

Related: NixOS/nixpkgs#24744 (lld has no nixpkgs wrapper).

Contributor guide

Open the contributing guide

First steps

  1. Read the whole issue, then the project's contributing guide.
  2. Comment on the issue to say you are picking it up — it saves two people doing the same work.
  3. Fork the repository and make your change on a branch.
  4. Open a pull request that references the issue number.

Research direction

Start by reproducing the provided Cargo build on NixOS and comparing rust-lld with the GNU ld path using readelf, ldd, and the supplied RUSTFLAGS. Then trace rustc's self-contained linker selection for x86_64-unknown-linux-gnu and how the cc wrapper supplies rpath flags. Done means the lost RUNPATH interaction is either handled or documented with a verified workaround.

Written by the indexing model from the issue text.

Assessment

Tech stack
rust
Domain
compilers
Issue type
Bug
Difficulty
4/5
Estimated time
3-5 days
Activity status
Active
Clarity
Mostly clear
Newbie friendliness
52/100

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.