Skip to content

feat: opt a target triple's stdlib out of the bundled libc - #245

Open
lsjostro wants to merge 1 commit into
hermeticbuild:mainfrom
lsjostro:stdlib-external-libc
Open

feat: opt a target triple's stdlib out of the bundled libc#245
lsjostro wants to merge 1 commit into
hermeticbuild:mainfrom
lsjostro:stdlib-external-libc

Conversation

@lsjostro

@lsjostro lsjostro commented Sep 3, 2026

Copy link
Copy Markdown
Contributor

Problem

rustc puts the prebuilt stdlib's self-contained directory on the linker search path ahead of the CC toolchain's -L, so -lc always resolves to the libc rustc ships. Anyone who builds their own sysroot — a distro, an OS image, an embedded target — silently links the wrong libc, and any patch carried in that libc (hardening flags, an allocator swap) never reaches a Rust binary.

Measured on 1.95.0, x86_64-unknown-linux-musl, with a CC toolchain whose --sysroot, -L and -B all point at a locally built musl. ld.lld -t shows:

ld.lld: .../rust_toolchain/lib/rustlib/x86_64-unknown-linux-musl/lib/self-contained/libc.a

The -L for self-contained sits at position 3 in lld's search list; the CC toolchain's is at position 10.

-C link-self-contained=no does not fix it — it leaves that -L in place, and the output is byte-identical with and without the flag. Dropping the files from the sandbox is the only lever I found.

Change

  • stdlib_repository also emits rust_std-<triple>-external-libc: the same stdlib without the archives under self-contained.
  • declare_rustc_toolchains takes external_libc_triples, a list of target triples that should use it. Explicit rust_std entries still win.

The CRT objects deliberately stay in the filtered filegroup. Remove the directory altogether and rustc stops using self-contained CRT, emitting bare rcrt1.o / crti.o names that the clang driver cannot resolve — that took a couple of iterations to find, so it is called out in a comment.

Usage

declare_rustc_toolchains(
    name = "patos",
    version = "1.95.0",
    edition = "2024",
    target_triples = ["x86_64-unknown-linux-musl", "aarch64-unknown-linux-musl"],
    external_libc_triples = ["x86_64-unknown-linux-musl", "aarch64-unknown-linux-musl"],
)

Verification

Applied via local_path_override in a workspace that builds musl from source and registers a CC toolchain against that sysroot. Before, the link pulled the bundled self-contained/libc.a; with external_libc_triples set and no other change, the same link pulls:

ld.lld: bazel-out/k8-fastbuild/bin/third_party/musl/musl/lib/libc.a
ld.lld: .../lib/rustlib/x86_64-unknown-linux-musl/lib/self-contained/rcrt1.o

— the workspace's libc, rustc's CRT. The resulting static-pie binaries run, and the workspace's test suite (including a VM boot of the produced image, both libc flavors) passes.

This replaced a local repo rule that symlinked the stdlib tree and regenerated a filtered filegroup, which is what motivated the PR.

Note

Independent of #244, though a consumer calling declare_rustc_toolchains from a workspace package rather than a generated repo wants that one too.

rustc puts the prebuilt stdlib's `self-contained` directory on the linker
search path ahead of the CC toolchain's `-L`, so `-lc` always resolves to
the libc rustc ships. A workspace that builds its own sysroot -- a distro,
an OS image, an embedded target -- silently links the wrong libc, and any
patch it carries in that libc never reaches a Rust binary.

`-C link-self-contained=no` does not help: it leaves the search path in
place (verified on 1.95.0, byte-identical output). The files have to leave
the sandbox instead, so the stdlib repo grows a second filegroup without
the archives, and `declare_rustc_toolchains` grows a triple list that
selects it.

The CRT objects stay in the filtered filegroup. Remove the directory
altogether and rustc stops using self-contained CRT, emitting bare
`rcrt1.o` / `crti.o` names that the clang driver cannot resolve.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant