Skip to content

node:http.createServer FFI symbols undefined in default Perry binary (follow-up to #589) #1652

Description

@proggeramlug

Scope

`perry-ext-http-server` is a real crate (crates/perry-ext-http-server/{lib,server,response,request,http2_server,https_server,tls,upgrade,types}.rs) with the FFI surface for node:http.createServer. But when a user program does import { createServer } from 'node:http' and Perry compiles with --features full (the default), the linker drops the symbols. The result is a hard link failure, not a runtime gap.

The docs page `docs/src/stdlib/http.md` still ships this paragraph:

"The canonical 'deploy a hono app as a native binary on a Linux VM' pattern — serve({ fetch: app.fetch, port: 3000 }) via @hono/node-server, or a hand-rolled node:http adapter that drives app.fetchcurrently fails to link because the Web Fetch FFIs (Headers / Response constructors) aren't pulled in alongside perry-ext-http-server. Tracked at issue #589."

#589 is closed but the link error reproduces today on both my local Perry 0.5.1026 and the worker's source-built 0.5.1025 (/opt/perry-src/target/release/perry, perry-src HEAD f46c4c3). So either the fix from #589 didn't cover this case, or it regressed.

Why

node:http working is the difference between writing a 50-line adapter (Perry-owned hyper does HTTP parsing) and either (a) hand-rolling 400 LOC of HTTP/1.1 framing on node:net, or (b) committing to Fastify as the only HTTP path in perpetuity. #577 chose path (a) for the architecture; closing this gap is what makes that real.

Repro (Perry 0.5.1026, perry-src commit f46c4c3; worker /opt/perry-src/target/release/perry 0.5.1025 reproduces identically)

```typescript
// nh-smoke.ts
import { createServer } from "node:http";
createServer((_req, res) => res.end("ok")).listen(0);
```

```bash
perry compile nh-smoke.ts -o nh-smoke
```

Observed:

```
Undefined symbols for architecture arm64:
"_js_node_http_create_server", referenced from: _main
"_js_node_http_server_listen", referenced from: _main
"_js_node_http_res_end", referenced from: _perry_closure_nh_smoke_ts__3
ld: symbol(s) not found for architecture arm64
clang: error: linker command failed with exit code 1
Error: Linking failed
```

(Linux worker yields equivalent undefined reference to \js_node_http_create_server`` etc. through GNU ld.)

Acceptance

  • The snippet above compiles and links cleanly with perry compile on a stock Perry binary (no extra flags).
  • ./nh-smoke &; curl -fsS http://127.0.0.1:<port>/anything returns ok with HTTP 200.
  • Add a CI smoke that compiles + runs that 2-line program once per Perry release so this can't silently regress again. Possibly extend to a 6-line variant that wires app.fetch from a new Hono(); app.get('/', c => c.text('ok')) through and reads the body — i.e. the docs example from stdlib/http.md becomes the test fixture.
  • When the fix lands, remove the "currently fails to link" paragraph from docs/src/stdlib/http.md.

Hypothesis on where the fix lives

The http-server cargo feature in crates/perry-stdlib/Cargo.toml transitively pulls bundled-fastify (per a comment in the file: "http-server umbrella retained for backwards-compat — it now transitively pulls bundled-fastify"), but the perry-ext-http-server symbols aren't being marked as #[used] / aren't on a path that survives LTO dead-code elimination. Sibling commits like b47459ed perry-stdlib+ext-net: refs #421/#420 — issue #91 HANDLE_METHOD_DISPATCH for perry-ext-net and 31e51bf4 perry-stdlib+ext-net: refs #421/#420 — net pump registration + LTO black-box ran into the same pattern with perry-ext-net and resolved it via LTO black-box + pump registration. Likely the same shape applies here.

Related

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions