Skip to content

thin-LTO strips #[no_mangle] C symbols from prebuilt ext staticlib archives (node:zlib link fails) #5669

Description

@proggeramlug

Summary

With lto = "thin" in [profile.release], building an ext crate as crate-type = ["staticlib", "rlib"] internalizes its #[no_mangle] C-ABI symbols in the resulting .a. The prebuilt target/release/libperry_ext_*.a archives export zero js_* symbols.

Crates the auto-optimizer rebuilds with shared tokio regain their symbols (they're recompiled), but CPU-only crates routed to the prebuilt .a (e.g. the compression crate for node:zlib, events) link against a symbol-less archive, so the final link fails with Undefined symbols: _js_ext_zlib_*, _js_zlib_create_*, … even though the archive is present and was logged as routed.

Evidence / repro

$ nm target/release/libperry_ext_zlib.a | grep -c ' T _js_zlib'
0
$ nm target/release/libperry_ext_http.a | grep -c ' T _js_'
0
$ CARGO_PROFILE_RELEASE_LTO=off cargo build --release -p perry-ext-zlib
$ nm target/release/libperry_ext_zlib.a | grep -c ' T _js_zlib'
26

A program that imports node:zlib then fails to link. (Note: setting CARGO_PROFILE_RELEASE_LTO=off as an env on perry compile does not propagate to the auto-optimizer's internal cargo invocations — the crate must be rebuilt directly.)

Workaround

Build the routed crate with CARGO_PROFILE_RELEASE_LTO=off so its staticlib keeps the #[no_mangle] exports.

Suggested fix

Build the routed/prebuilt ext staticlibs with thin-LTO disabled (or otherwise preserve the #[no_mangle] C exports — e.g. #[used] / an explicit export list / -C linker-plugin-lto), independent of the shared-tokio rebuild path. Affects any program importing a non-tokio well-known ext crate (compression, events, …).

Related: the auto-optimizer "archives-fresh" fast-path also dropped these routed libs from the link line — separate fix in #5668. Both are needed to link a node:zlib program from fresh archives.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type
    No fields configured for issues without a type.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions