From 57a063b7ab49fda26d544b42a8bd4c1e811eed8b Mon Sep 17 00:00:00 2001 From: Ralph Date: Sat, 4 Jul 2026 02:24:25 -0700 Subject: [PATCH 1/2] =?UTF-8?q?fix(build):=20#5928=20=E2=80=94=20match=20c?= =?UTF-8?q?odegen-units=20across=20perry-stdlib-static=20and=20well-known?= =?UTF-8?q?=20ext=20crates?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit perry-stdlib-static/perry-runtime-static override codegen-units=16 (#5140, preserving #[no_mangle] extern "C" exports from thin-LTO internalization), but the well-known "shared tokio" (#507) ext crates (perry-ext-fastify/ http/ioredis/net/ws) had no override and used the workspace default of 1. Cargo builds them in the same invocation as perry-stdlib-static so their dependency graphs are unified, but that unification doesn't survive a codegen-units mismatch: rustc partitions each crate's monomorphized code into that many codegen units, so the "same" shared dependency (e.g. compiler_builtins) ends up split differently across crates with different settings, producing non-identical objects perry's strip-dedup can't safely treat as interchangeable duplicates. Confirmed via md5: compiler_builtins' codegen units are now byte-identical between libperry_ext_http.a and libperry_stdlib.a (231/231), versus divergent sizes before this fix (e.g. the shared `core` unit was 2.4 MB in the ext lib vs 551 KB in stdlib). This narrows but does not close #5928's duplicate-symbol gap: most shared dependencies (tokio, hyper_util, rustls, ring, ...) are pulled into perry-stdlib-static's own linker-plugin-lto merge and can never be byte-identical to a plain compile of the same crate regardless of matching settings — see the follow-up commit and #5928 for the residual analysis. --- Cargo.toml | 42 ++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 42 insertions(+) diff --git a/Cargo.toml b/Cargo.toml index 2f688c3067..c27c412a16 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -229,6 +229,34 @@ codegen-units = 16 strip = false codegen-units = 16 +# Issue #5928: well-known "shared tokio" wrapper crates (#507) are built in +# the SAME cargo invocation as perry-stdlib-static so cargo unifies their +# shared dependency graph (tokio, hyper_util, rustls, and even core/std +# monomorphizations) into identical compilation units. That unification only +# holds if EVERY crate in that invocation uses the SAME `codegen-units` +# setting — rustc partitions a crate's monomorphized code into N codegen +# units based on this value, so two crates compiling the "same" shared +# dependency with different `codegen-units` end up with differently-sized, +# differently-partitioned .rcgu.o objects despite sharing an identical +# crate/feature graph (confirmed empirically: perry-stdlib-static's `core` +# codegen unit was 551 KB vs an ext crate's 2.4 MB for the identically +# hash-named unit, before this fix). Without this, macOS's linker (which +# has no `-multiply_defined suppress` / `-ld_classic` tolerance mode +# anymore) hits thousands of `ld: duplicate symbol` errors once a program +# needs 2+ of these wrapper crates simultaneously, because perry's +# strip-dedup mechanism assumes same-named codegen units are byte-identical +# and safe to drop duplicates from — an assumption this mismatch violated. +[profile.release.package.perry-ext-fastify] +codegen-units = 16 +[profile.release.package.perry-ext-http] +codegen-units = 16 +[profile.release.package.perry-ext-ioredis] +codegen-units = 16 +[profile.release.package.perry-ext-net] +codegen-units = 16 +[profile.release.package.perry-ext-ws] +codegen-units = 16 + # Fast developer profile (#5422). Optimized enough for realistic local runs but # without the distribution-grade settings that dominate compile time, so the # edit/build loop stays short. Intended local loop: @@ -300,6 +328,20 @@ codegen-units = 16 strip = false codegen-units = 16 +# Issue #5928: mirrors the [profile.release.package.perry-ext-*] block above +# — see its comment for why matching `codegen-units` across every crate in +# the "shared tokio" (#507) cargo invocation is required. +[profile.dist.package.perry-ext-fastify] +codegen-units = 16 +[profile.dist.package.perry-ext-http] +codegen-units = 16 +[profile.dist.package.perry-ext-ioredis] +codegen-units = 16 +[profile.dist.package.perry-ext-net] +codegen-units = 16 +[profile.dist.package.perry-ext-ws] +codegen-units = 16 + [workspace.package] version = "0.5.1236" edition = "2021" From 8c0e742b0e9dc6b7e83a027b2c1eace356583b63 Mon Sep 17 00:00:00 2001 From: Ralph Date: Sat, 4 Jul 2026 02:24:35 -0700 Subject: [PATCH 2/2] =?UTF-8?q?fix(compile):=20#5928=20=E2=80=94=20restore?= =?UTF-8?q?=20well-known=20lib=20dedup=20on=20cold=20auto-optimize=20build?= =?UTF-8?q?s?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit build_optimized_libs() has three return paths that construct the final OptimizedLibs. Two correctly set prefer_well_known_before_stdlib from whether any well-known libs are in play; the third — reached when the well-known native libs must be built from scratch (a cold/cleared auto-optimize cache, not the "archives are fresh" fast path) — hardcoded it to `false`. That flag gates whether build_and_run.rs runs strip_bundled_runtime_from_ well_known_lib / strip_bundled_shared_deps_from_well_known_lib at link time. With it forced false, a program needing 2+ well-known libs together (e.g. opencode's fastify + http + ioredis + net + ws) skipped dedup entirely on any build that couldn't reuse cached archives, silently and non-fatally regressing to raw (undeduped) linking — confirmed by comparing duplicate-symbol counts with and without a stale auto-optimize directory present (2152 vs 1382 for the same program). Match the other two branches: prefer_well_known_before_stdlib should depend only on whether there are well-known libs to dedup, not on which of the three build/cache paths produced them. --- crates/perry/src/commands/compile/optimized_libs/driver.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/crates/perry/src/commands/compile/optimized_libs/driver.rs b/crates/perry/src/commands/compile/optimized_libs/driver.rs index 05100544f3..2350dd423a 100644 --- a/crates/perry/src/commands/compile/optimized_libs/driver.rs +++ b/crates/perry/src/commands/compile/optimized_libs/driver.rs @@ -1069,7 +1069,7 @@ pub(crate) fn build_optimized_libs( runtime_bc, stdlib_bc, extra_bc, + prefer_well_known_before_stdlib: !well_known_libs.is_empty(), well_known_libs, - prefer_well_known_before_stdlib: false, } }