Summary
A cold auto-optimize link of any program importing node:http fails with an undefined symbol. Found while validating an unrelated PR; reproduces independently of it, and the causal chain is visible in the source on main.
Undefined symbols for architecture arm64:
"_js_bun_http_response_snapshot_json", referenced from:
perry_ext_http::server::bun_server::settle_value in
libperry_ext_http.a(...perry_ext_http...cgu.10.rcgu.o)
ld: symbol(s) not found for architecture arm64
clang: error: linker command failed with exit code 1
Error: Linking failed
Repro
// http_server.ts
import http from "node:http";
const server = http.createServer((req, res) => { res.end("{}"); });
server.listen(0, () => { console.log("listening"); server.close(); });
perry compile http_server.ts -o http_server from a cold cache (fresh
node_modules/.cache/perry, no warm target/perry-auto-*). A warm cache built
before this masks it, which is part of why it is not visible day to day.
Cause
js_bun_http_response_snapshot_json is defined in
crates/perry-stdlib/src/fetch/bun_server_bridge.rs:79. mod bun_server_bridge
is ungated, but its parent is not — crates/perry-stdlib/src/lib.rs:136:
#[cfg(feature = "web-fetch")]
pub mod fetch;
The auto-optimize rebuild for a node:http program selects
async-runtime, external-http-client-pump, external-http-server-pump,
external-net-tls, external-tls-server, external-ws-pump
which does not include web-fetch, so the whole fetch module — and the
symbol — is compiled out. Meanwhile perry-ext-http's
server/bun_server.rs declares and calls it unconditionally (3 references on
main). Definition and reference disagree about the feature that gates them.
Why CI is green
This is the CI-invisible class recorded in changelog.d/memory around #5112:
plain cargo build / cargo test never link the auto-optimize ext-http path,
so nothing in the normal suites exercises it, and any pre-existing warm
target/perry-auto-* cache hides it from a manual check too. Only a fresh
cold auto-opt link surfaces it.
Fix shapes
- Gate
perry-ext-http's use of the bridge on the same feature that gates its
definition, so the two cannot disagree.
- Have the driver add
web-fetch whenever it selects the http server features
(widens the build).
- Move
js_bun_http_response_snapshot_json out of the web-fetch-gated module
into one that is always compiled when external-http-server-pump is on.
(1) or (3) look right; (2) treats the symptom.
Worth a gate either way: a cold-cache node:http compile-and-run in the tier
that already builds package smokes would have caught this, and would catch the
next instance of the same class.
Summary
A cold auto-optimize link of any program importing
node:httpfails with an undefined symbol. Found while validating an unrelated PR; reproduces independently of it, and the causal chain is visible in the source onmain.Repro
perry compile http_server.ts -o http_serverfrom a cold cache (freshnode_modules/.cache/perry, no warmtarget/perry-auto-*). A warm cache builtbefore this masks it, which is part of why it is not visible day to day.
Cause
js_bun_http_response_snapshot_jsonis defined incrates/perry-stdlib/src/fetch/bun_server_bridge.rs:79.mod bun_server_bridgeis ungated, but its parent is not —
crates/perry-stdlib/src/lib.rs:136:The auto-optimize rebuild for a
node:httpprogram selectswhich does not include
web-fetch, so the wholefetchmodule — and thesymbol — is compiled out. Meanwhile
perry-ext-http'sserver/bun_server.rsdeclares and calls it unconditionally (3 references onmain). Definition and reference disagree about the feature that gates them.Why CI is green
This is the CI-invisible class recorded in
changelog.d/memory around #5112:plain
cargo build/cargo testnever link the auto-optimize ext-http path,so nothing in the normal suites exercises it, and any pre-existing warm
target/perry-auto-*cache hides it from a manual check too. Only a freshcold auto-opt link surfaces it.
Fix shapes
perry-ext-http's use of the bridge on the same feature that gates itsdefinition, so the two cannot disagree.
web-fetchwhenever it selects the http server features(widens the build).
js_bun_http_response_snapshot_jsonout of theweb-fetch-gated moduleinto one that is always compiled when
external-http-server-pumpis on.(1) or (3) look right; (2) treats the symptom.
Worth a gate either way: a cold-cache
node:httpcompile-and-run in the tierthat already builds package smokes would have caught this, and would catch the
next instance of the same class.