Fix Linux cross-build to use the rustls backend (musl)

ober

20979c71f47cf99f8c299fa4f85a2ed4316b6420

diff --git a/.gitignore b/.gitignore
index 7f8b390..b445fb1 100644
--- a/.gitignore
+++ b/.gitignore
@@ -6,9 +6,13 @@
 *.so
 *.wpo
 *.boot
+# Host-side emit artifacts from the cross-build (ta6le emit mode)
+*.tarm64osx
+*.ta6le
 
 # Generated by the build (see support/gen-ffi-symbols.sh and cross scripts)
 support/ffi-symbols.gen
+support/ffi-symbols-linux.gen
 jgl-main.c
 jgl-*-main.c
 *_boot.h
diff --git a/Makefile b/Makefile
index b4f6c1b..ac6cc53 100644
--- a/Makefile
+++ b/Makefile
@@ -16,12 +16,21 @@ BIN_DIR    := $(HOME)/.local/bin
 # loader at jerbuild's cache for `make run`/`make test`.
 DYLD := DYLD_FALLBACK_LIBRARY_PATH="$(NATIVE_DIR)" LD_LIBRARY_PATH="$(NATIVE_DIR):$$LD_LIBRARY_PATH"
 
-# Cross-compilation prerequisites (shared across the jerboa-* family).
+# --- Cross-compilation (macOS -> Linux x86_64 musl) ---
+# jgl's HTTPS uses rustls (jerboa-native), so the cross build links a musl-cross
+# build of that crate (not the OpenSSL shim). Requires: a full Chez 'scheme'
+# (falls back to the jerboa build tree), the cross-built Chez + xpatch under
+# JERBOA_HOME, x86_64-linux-musl-gcc, and a rustup toolchain with the
+# x86_64-unknown-linux-musl target (the recipe cargo-builds the crate).
 JERBOA_HOME   ?= $(HOME)/mine/jerboa
-SCHEME        ?= scheme
-CROSS_LIBDIRS ?= lib:$(JERBOA_HOME)/lib:$(HOME)/mine/jerboa-https/src:$(HOME)/mine/jerboa-ssl/src
+SCHEME        ?= $(shell command -v scheme 2>/dev/null || echo $(JERBOA_HOME)/build/chez/tarm64osx/bin/tarm64osx/scheme)
+CROSS_LIBDIRS ?= lib:$(JERBOA_HOME)/lib
+RUSTUP_TC     ?= stable
+MUSL_TARGET   := x86_64-unknown-linux-musl
+MUSL_CC       ?= x86_64-linux-musl-gcc
+NATIVE_MUSL_A := $(JH)/jerboa-native-rs/target/$(MUSL_TARGET)/release/libjerboa_native.a
 
-.PHONY: all build binary run test install clean help cross-linux cross-freebsd
+.PHONY: all build binary run test install clean help cross-linux
 .DEFAULT_GOAL := help
 
 all: binary
@@ -48,17 +57,25 @@ install: binary
 	install -m 0755 $(BIN) $(BIN_DIR)/$(BIN)
 	@echo "Installed $(BIN) to $(BIN_DIR)/$(BIN)"
 
-# Cross-compile from macOS to Linux x86_64 musl (static) / FreeBSD 14 amd64.
-# See build-jgl-*-cross.ss headers for the required cross toolchain.
+# Cross-compile macOS -> Linux x86_64 musl (static). Builds the rustls native
+# crate for musl, lists its FFI symbols, then cross-links jgl-linux-amd64.
 cross-linux:
-	JERBOA_HOME=$(JERBOA_HOME) $(SCHEME) -q --libdirs $(CROSS_LIBDIRS) --script build-jgl-cross.ss
-
-cross-freebsd:
-	JERBOA_HOME=$(JERBOA_HOME) $(SCHEME) -q --libdirs $(CROSS_LIBDIRS) --script build-jgl-freebsd-cross.ss
+	cd $(JH)/jerboa-native-rs && \
+	  RUSTC="$$(rustup which --toolchain $(RUSTUP_TC) rustc)" \
+	  CC_x86_64_unknown_linux_musl=$(MUSL_CC) \
+	  AR_x86_64_unknown_linux_musl=x86_64-linux-musl-ar \
+	  CARGO_TARGET_X86_64_UNKNOWN_LINUX_MUSL_LINKER=$(MUSL_CC) \
+	  "$$(rustup which --toolchain $(RUSTUP_TC) cargo)" build --release \
+	    --target $(MUSL_TARGET) --no-default-features --features tls,crypto
+	x86_64-linux-musl-nm -g --defined-only $(NATIVE_MUSL_A) | awk '{print $$NF}' \
+	  | grep -E '^jerboa_[A-Za-z0-9_]+$$' | sort -u > support/ffi-symbols-linux.gen
+	JERBOA_HOME=$(JERBOA_HOME) JGL_NATIVE_A=$(NATIVE_MUSL_A) \
+	  JGL_FFI_SYMBOLS=support/ffi-symbols-linux.gen \
+	  $(SCHEME) -q --libdirs $(CROSS_LIBDIRS) --script build-jgl-cross.ss
 
 clean:
-	rm -f $(BIN) jgl-linux-amd64 jgl-freebsd-amd64 jgl-*main.c *.h *.boot *.wp.so
-	find . \( -name '*.so' -o -name '*.wpo' \) -delete 2>/dev/null || true
+	rm -f $(BIN) jgl-linux-amd64 jgl-*main.c *.h *.boot *.wp.so
+	find . \( -name '*.so' -o -name '*.wpo' -o -name '*.tarm64osx' -o -name '*.ta6le' \) -delete 2>/dev/null || true
 
 help:
 	@echo "jerboa-gitlab -- the jgl GitLab CLI (jerbuild + cargo + cc)"
@@ -67,6 +84,5 @@ help:
 	@echo "  make run ARGS='...'    Build + run ./jgl"
 	@echo "  make test             Run the test suite"
 	@echo "  make install          Build + install to ~/.local/bin/jgl"
-	@echo "  make cross-linux      Cross-build jgl-linux-amd64 (musl static)"
-	@echo "  make cross-freebsd    Cross-build jgl-freebsd-amd64"
+	@echo "  make cross-linux      Cross-build jgl-linux-amd64 (musl static, rustls)"
 	@echo "  make clean            Remove build artifacts"
diff --git a/README.md b/README.md
index 9a263bc..4a9807b 100644
--- a/README.md
+++ b/README.md
@@ -112,19 +112,29 @@ download fails the original link is left intact.
 
 ## Cross-compilation
 
-The `make binary` path is portable (it runs natively on each OS). To build
-Linux/FreeBSD binaries *from macOS*, two scripts adapt the proven
-`jerboa-aws` cross pattern (which uses the `jerboa-ssl`/OpenSSL static path):
+`make binary` is portable — it runs natively on macOS, Linux, and FreeBSD. To
+build a Linux x86_64 binary *from macOS*:
 
 ```sh
-make cross-linux      # -> jgl-linux-amd64   (x86_64 musl, static)
-make cross-freebsd    # -> jgl-freebsd-amd64 (x86_64, dynamic)
+make cross-linux      # -> jgl-linux-amd64  (static musl ELF)
 ```
 
-These require the shared cross toolchain used across the `jerboa-*` family —
-a cross-built Chez install, the `jerboa-ssl` shim object, and musl-OpenSSL /
-a FreeBSD sysroot. See the headers of `build-jgl-cross.ss` and
-`build-jgl-freebsd-cross.ss` for the exact prerequisites and env overrides.
+jgl's HTTPS uses rustls (the `jerboa-native` crate), so this cross-builds that
+crate for `x86_64-unknown-linux-musl` and static-links it — the same TLS
+backend as the native build (not the OpenSSL shim some older `jerboa-*` cross
+scripts use). It needs:
+
+- a full Chez `scheme` compiler — the Makefile falls back to
+  `$JERBOA_HOME/build/chez/tarm64osx/bin/tarm64osx/scheme` if none is on PATH;
+- the cross-built Chez + xpatch under `$JERBOA_HOME` (`.chez-cross-ta6le`,
+  `build/chez/xc-ta6le/s/xpatch`);
+- `x86_64-linux-musl-gcc`;
+- a rustup toolchain with the musl target (`rustup target add x86_64-unknown-linux-musl`).
+
+Override `JERBOA_HOME`, `SCHEME`, `RUSTUP_TC`, or `MUSL_CC` on the make line as
+needed; see `build-jgl-cross.ss` for the details. (A FreeBSD cross would follow
+the same shape with the `x86_64-unknown-freebsd` Rust target + a sysroot; not
+wired up yet.)
 
 ## Layout
 
diff --git a/build-jgl-cross.ss b/build-jgl-cross.ss
index 57d6b95..dea4860 100644
--- a/build-jgl-cross.ss
+++ b/build-jgl-cross.ss
@@ -1,46 +1,45 @@
 #!chezscheme
 ;;; build-jgl-cross.ss — Cross-compile jgl from macOS arm64 to Linux x86_64 musl.
 ;;;
-;;; Usage (from the repo root):
-;;;   JERBOA_HOME=$HOME/mine/jerboa scheme -q \
-;;;     --libdirs lib:$HOME/mine/jerboa/lib:$HOME/mine/jerboa-https/src:$HOME/mine/jerboa-ssl/src \
-;;;     --script build-jgl-cross.ss
-;;;   (or: make cross-linux)
+;;; jgl's HTTPS client uses (std net request) -> (std net tls-rustls), i.e. the
+;;; Rust `jerboa-native` crate (rustls). So the cross binary must link a
+;;; musl-cross build of that crate and register its jerboa_* FFI symbols — the
+;;; same backend as the native `jerbuild build`. (The jerboa-ssl/OpenSSL shim
+;;; path used by older jerboa-* cross scripts only provides jerboa_ssl_*/
+;;; jerboa_tcp_* and would fail at runtime on jerboa_tls_connect.)
 ;;;
-;;; Adapted from jerboa-aws/build-jaws-cross.ss — jgl uses the identical
-;;; (std net request) networking stack, so the same SSL-shim static-link path
-;;; applies. Prerequisites (built once, shared across the jerboa-* family):
-;;;   - $JERBOA_HOME/.chez-cross-ta6le/   — cross-built Chez install (ta6le)
-;;;   - $JERBOA_HOME/build/chez/xc-ta6le/s/xpatch — host -> ta6le emit-mode loader
-;;;   - x86_64-linux-musl-gcc             — C compile + final static link
-;;;   - ~/mine/jerboa-ssl/jerboa_ssl_shim-linux-musl.o  (built by jerboa-ssl Makefile)
-;;;   - ~/musl-openssl/usr/{lib,include}   — Alpine static libssl.a + libcrypto.a
+;;; Driven by `make cross-linux`, which first cargo-builds the crate for
+;;; x86_64-unknown-linux-musl and writes the symbol list. Inputs via env:
+;;;   JGL_NATIVE_A    path to musl libjerboa_native.a
+;;;   JGL_FFI_SYMBOLS file of jerboa_* symbols (one per line) to register
+;;;   JERBOA_HOME     jerboa source checkout (cross Chez + stdlib)
+;;;   CROSS_CC        musl gcc (default x86_64-linux-musl-gcc)
+;;;
+;;; Prerequisites (shared across the jerboa-* family):
+;;;   - $JERBOA_HOME/.chez-cross-ta6le/             cross-built Chez (ta6le)
+;;;   - $JERBOA_HOME/build/chez/xc-ta6le/s/xpatch   host -> ta6le emit loader
+;;;   - x86_64-linux-musl-gcc                       C compile + static link
+;;;   - rustup target x86_64-unknown-linux-musl     (the Makefile builds the .a)
 ;;;
 ;;; Produces: jgl-linux-amd64 (static Linux x86_64 ELF).
 
 (import (chezscheme))
 
 ;; ── Params ──────────────────────────────────────────────────────────────────
-(define jerboa-home
-  (or (getenv "JERBOA_HOME") "/Users/user/mine/jerboa"))
-
+(define jerboa-home (or (getenv "JERBOA_HOME") "/Users/user/mine/jerboa"))
 (define cross-prefix (format "~a/.chez-cross-ta6le" jerboa-home))
 (define xpatch       (format "~a/build/chez/xc-ta6le/s/xpatch" jerboa-home))
 (define cross-cc     (or (getenv "CROSS_CC") "x86_64-linux-musl-gcc"))
-
 (define output       "jgl-linux-amd64")
 (define entry-script "jgl.ss")
+(define jgl-repo     (current-directory))
 
-(define jgl-repo (current-directory))
-(define jerboa-ssl-repo
-  (or (getenv "JERBOASSL_REPO") (format "~a/mine/jerboa-ssl" (getenv "HOME"))))
-(define jerboa-https-repo
-  (or (getenv "JERBOAHTTPS_REPO") (format "~a/mine/jerboa-https" (getenv "HOME"))))
-(define jerboa-ssl-shim-o
-  (or (getenv "JERBOA_SSL_SHIM_LINUX_O")
-      (format "~a/jerboa_ssl_shim-linux-musl.o" jerboa-ssl-repo)))
-(define musl-openssl-dir
-  (or (getenv "MUSL_OPENSSL_DIR") (format "~a/musl-openssl" (getenv "HOME"))))
+(define native-a
+  (or (getenv "JGL_NATIVE_A")
+      (error 'build-jgl-cross "set JGL_NATIVE_A to the musl libjerboa_native.a (use 'make cross-linux')")))
+(define ffi-symbols-file
+  (or (getenv "JGL_FFI_SYMBOLS")
+      (error 'build-jgl-cross "set JGL_FFI_SYMBOLS to the jerboa_* symbol list (use 'make cross-linux')")))
 
 (define cross-csv-dir
   (let ([lib (format "~a/lib" cross-prefix)])
@@ -56,40 +55,52 @@
       (format "~a/~a/ta6le" lib (car csvs)))))
 
 (define (require-file p)
-  (unless (file-exists? p)
-    (error 'build-jgl-cross "missing file" p)))
+  (unless (file-exists? p) (error 'build-jgl-cross "missing file" p)))
 
 (require-file xpatch)
-(require-file (format "~a/libkernel.a"  cross-csv-dir))
-(require-file (format "~a/scheme.h"     cross-csv-dir))
-(require-file (format "~a/petite.boot"  cross-csv-dir))
-(require-file (format "~a/scheme.boot"  cross-csv-dir))
+(require-file (format "~a/libkernel.a" cross-csv-dir))
+(require-file (format "~a/scheme.h"    cross-csv-dir))
+(require-file (format "~a/petite.boot" cross-csv-dir))
+(require-file (format "~a/scheme.boot" cross-csv-dir))
 (require-file entry-script)
-(require-file jerboa-ssl-shim-o)
-(require-file (format "~a/usr/lib/libssl.a"    musl-openssl-dir))
-(require-file (format "~a/usr/lib/libcrypto.a" musl-openssl-dir))
-
-(printf "==> build-jgl-cross~n")
-(printf "    JERBOA_HOME:     ~a~n" jerboa-home)
-(printf "    cross csv-dir:   ~a~n" cross-csv-dir)
-(printf "    xpatch:          ~a~n" xpatch)
-(printf "    cross-cc:        ~a~n" cross-cc)
-(printf "    jerboa-ssl shim:   ~a~n" jerboa-ssl-shim-o)
-(printf "    musl openssl:    ~a~n" musl-openssl-dir)
-(printf "    output:          ~a~n" output)
-(printf "~n")
+(require-file native-a)
+(require-file ffi-symbols-file)
+
+;; Read the jerboa_* symbols to register with Sforeign_symbol.
+(define jerboa-symbols
+  (call-with-input-file ffi-symbols-file
+    (lambda (p)
+      (let loop ([acc '()])
+        (let ([line (get-line p)])
+          (if (eof-object? line)
+            (reverse acc)
+            (let ([s (let trim ([i 0])
+                       (if (and (< i (string-length line))
+                                (memv (string-ref line i) '(#\space #\tab)))
+                         (trim (+ i 1))
+                         (substring line i (string-length line))))])
+              (if (and (>= (string-length s) 7) (string=? (substring s 0 7) "jerboa_"))
+                (loop (cons s acc))
+                (loop acc)))))))))
+
+(printf "==> build-jgl-cross (rustls/musl)~n")
+(printf "    JERBOA_HOME:   ~a~n" jerboa-home)
+(printf "    cross csv-dir: ~a~n" cross-csv-dir)
+(printf "    cross-cc:      ~a~n" cross-cc)
+(printf "    native .a:     ~a~n" native-a)
+(printf "    ffi symbols:   ~a (~a symbols)~n" ffi-symbols-file (length jerboa-symbols))
+(printf "    output:        ~a~n~n" output)
+(when (null? jerboa-symbols)
+  (error 'build-jgl-cross "no jerboa_* symbols found in" ffi-symbols-file))
 
 ;; ── Stage 1: load xpatch (target=ta6le emit mode) ──────────────────────────
-;; xpatch resets library-directories; restore + extend with our source libdirs.
 (define orig-libdirs (library-directories))
 (printf "==> [1/6] loading xpatch (compiler -> ta6le emit mode)~n")
 (load xpatch)
 (library-directories
   (append
-    (list (cons (format "~a/lib" jgl-repo)        (format "~a/lib" jgl-repo))
-          (cons (format "~a/lib" jerboa-home)     (format "~a/lib" jerboa-home))
-          (cons (format "~a/src" jerboa-https-repo) (format "~a/src" jerboa-https-repo))
-          (cons (format "~a/src" jerboa-ssl-repo)   (format "~a/src" jerboa-ssl-repo)))
+    (list (cons (format "~a/lib" jgl-repo)    (format "~a/lib" jgl-repo))
+          (cons (format "~a/lib" jerboa-home) (format "~a/lib" jerboa-home)))
     orig-libdirs))
 
 (compile-imported-libraries #t)
@@ -98,7 +109,6 @@
 ;; ── Stage 2: compile-program jgl.ss ─────────────────────────────────────────
 (printf "==> [2/6] compile-program ~a~n" entry-script)
 (compile-program entry-script)
-
 (define entry-wpo
   (let ([n (string-length entry-script)])
     (string-append (substring entry-script 0 (- n 3)) ".wpo")))
@@ -113,9 +123,7 @@
   (let* ([bv (call-with-port (open-file-input-port in-path) get-bytevector-all)]
          [n (bytevector-length bv)])
     (call-with-port (open-file-output-port out-path
-                       (file-options no-fail)
-                       (buffer-mode block)
-                       (native-transcoder))
+                       (file-options no-fail) (buffer-mode block) (native-transcoder))
       (lambda (out)
         (display (format "static const unsigned char ~a[] = {\n" var-name) out)
         (let loop ([i 0])
@@ -125,9 +133,7 @@
             (loop (+ i 1))))
         (when (positive? n) (newline out))
         (display "};\n" out)
-        (display (format "static const unsigned int ~a_size = sizeof(~a);\n"
-                         var-name var-name)
-                 out)))
+        (display (format "static const unsigned int ~a_size = sizeof(~a);\n" var-name var-name) out)))
     (printf "    embed ~a (~a bytes) -> ~a~n" in-path n out-path)))
 
 (printf "==> [4/6] embed boot files + program as C arrays~n")
@@ -135,26 +141,9 @@
 (embed-as-c-array (format "~a/scheme.boot" cross-csv-dir) "scheme_boot" "scheme_boot.h")
 (embed-as-c-array wpo-output                              "jgl_program" "jgl_program.h")
 
-;; ── Stage 5: generate main.c ───────────────────────────────────────────────
+;; ── Stage 5: generate main.c (registers the crate's jerboa_* symbols) ───────
 (define main-c-path (string-append output "-main.c"))
-
-;; jerboa-ssl/jerboa_ssl_shim.c symbol surface — must match the foreign-procedure
-;; declarations in jerboa-ssl.sls.
-(define jerboa-ssl-symbols
-  '("jerboa_ssl_init"        "jerboa_ssl_cleanup"
-    "jerboa_ssl_connect"     "jerboa_ssl_write"      "jerboa_ssl_read"
-    "jerboa_ssl_read_all"    "jerboa_ssl_free_buf"   "jerboa_ssl_close"
-    "jerboa_ssl_memcpy"
-    "jerboa_ssl_server_ctx"  "jerboa_ssl_server_accept" "jerboa_ssl_server_ctx_free"
-    "jerboa_tcp_listen"      "jerboa_tcp_accept"
-    "jerboa_tcp_connect"     "jerboa_tcp_close"
-    "jerboa_tcp_read"        "jerboa_tcp_write"      "jerboa_tcp_read_all"
-    "jerboa_tcp_set_timeout"
-    "jerboa_tcp_conn_wrap"
-    "jerboa_conn_write"      "jerboa_conn_read"))
-
-(printf "==> [5/6] generate ~a (~a jerboa-ssl symbols)~n"
-        main-c-path (length jerboa-ssl-symbols))
+(printf "==> [5/6] generate ~a (~a jerboa_* symbols)~n" main-c-path (length jerboa-symbols))
 
 (define (write-main-c)
   (call-with-port
@@ -163,36 +152,24 @@
     (lambda (out)
       (display "/* Auto-generated by build-jgl-cross.ss. Do not edit. */\n" out)
       (display "#define _GNU_SOURCE\n" out)
-      (display "#include <stdio.h>\n" out)
-      (display "#include <stdlib.h>\n" out)
-      (display "#include <string.h>\n" out)
-      (display "#include <unistd.h>\n" out)
-      (display "#include <sys/mman.h>\n" out)
-      (display "#include <fcntl.h>\n" out)
-      (display "#include \"scheme.h\"\n" out)
-      (display "#include \"petite_boot.h\"\n" out)
-      (display "#include \"scheme_boot.h\"\n" out)
-      (display "#include \"jgl_program.h\"\n\n" out)
-
-      ;; dlopen stubs (musl-static has no dlopen)
-      (display "/* dlopen stubs for static linking. Returning non-NULL for any\n" out)
-      (display " * named load makes (load-shared-object \"...\") succeed silently;\n" out)
-      (display " * foreign-procedure lookup uses Sforeign_symbol-registered entries. */\n" out)
-      (display "void *dlopen(const char *f, int flags) { (void)f; (void)flags; return (void*)1; }\n" out)
-      (display "void *dlsym(void *h, const char *s)    { (void)h; (void)s; return NULL; }\n" out)
-      (display "int   dlclose(void *h)                  { (void)h; return 0; }\n" out)
-      (display "static char dlerror_msg[] = \"static binary: dlopen stubbed\";\n" out)
-      (display "char *dlerror(void) { return dlerror_msg; }\n\n" out)
-
-      ;; extern decls for jerboa-ssl symbols
-      (display "/* jerboa_ssl_shim.o exports — registered with Sforeign_symbol below. */\n" out)
-      (for-each
-        (lambda (sym) (display (format "extern void ~a(void);\n" sym) out))
-        jerboa-ssl-symbols)
+      (display "#include <stdio.h>\n#include <stdlib.h>\n#include <string.h>\n" out)
+      (display "#include <unistd.h>\n#include <sys/mman.h>\n#include <fcntl.h>\n" out)
+      (display "#include \"scheme.h\"\n#include \"petite_boot.h\"\n" out)
+      (display "#include \"scheme_boot.h\"\n#include \"jgl_program.h\"\n\n" out)
+
+      ;; dlopen stubs (musl-static has no dlopen); FFI uses the Sforeign_symbol table.
+      (display "void *dlopen(const char *f, int g){ (void)f;(void)g; return (void*)1; }\n" out)
+      (display "void *dlsym(void *h, const char *s){ (void)h;(void)s; return NULL; }\n" out)
+      (display "int   dlclose(void *h){ (void)h; return 0; }\n" out)
+      (display "static char dlerr[] = \"static binary: dlopen stubbed\";\n" out)
+      (display "char *dlerror(void){ return dlerr; }\n\n" out)
+
+      (display "/* jerboa-native (rustls/crypto) exports — registered below. */\n" out)
+      (for-each (lambda (sym) (display (format "extern void ~a(void);\n" sym) out))
+                jerboa-symbols)
       (newline out)
 
       (display "int main(int argc, char *argv[]) {\n" out)
-      (display "    /* Argv passthrough via env vars (matches the native jgl main). */\n" out)
       (display "    char countbuf[32];\n" out)
       (display "    snprintf(countbuf, sizeof(countbuf), \"%d\", argc - 1);\n" out)
       (display "    setenv(\"JGL_ARGC\", countbuf, 1);\n" out)
@@ -202,7 +179,6 @@
       (display "        setenv(name, argv[i], 1);\n" out)
       (display "    }\n\n" out)
 
-      ;; Memfd-backed program path
       (display "    int fd = memfd_create(\"jgl-program\", MFD_CLOEXEC);\n" out)
       (display "    if (fd < 0) { perror(\"memfd_create\"); return 1; }\n" out)
       (display "    if (write(fd, jgl_program, jgl_program_size) != (ssize_t)jgl_program_size) {\n" out)
@@ -215,45 +191,32 @@
       (display "    Sregister_boot_file_bytes(\"petite\", (void*)petite_boot, petite_boot_size);\n" out)
       (display "    Sregister_boot_file_bytes(\"scheme\", (void*)scheme_boot, scheme_boot_size);\n\n" out)
 
-      (display "    /* Register jerboa_ssl_shim symbols so a -static binary resolves\n" out)
-      (display "     * (foreign-procedure \"jerboa_ssl_*\" ...) without dlsym. */\n" out)
-      (for-each
-        (lambda (sym)
-          (display (format "    Sforeign_symbol(\"~a\", (void*)~a);\n" sym sym) out))
-        jerboa-ssl-symbols)
+      (display "    /* Register jerboa-native symbols so a -static binary resolves\n" out)
+      (display "     * (foreign-procedure \"jerboa_*\" ...) without dlsym. */\n" out)
+      (for-each (lambda (sym)
+                  (display (format "    Sforeign_symbol(\"~a\", (void*)~a);\n" sym sym) out))
+                jerboa-symbols)
       (newline out)
 
       (display "    Sbuild_heap(NULL, NULL);\n" out)
       (display "    const char *script_args[] = { argv[0] };\n" out)
-      (display "    int status = Sscheme_program(prog_path, 1, script_args);\n\n" out)
-      (display "    close(fd);\n" out)
-      (display "    Sscheme_deinit();\n" out)
-      (display "    return status;\n" out)
-      (display "}\n" out))))
+      (display "    int status = Sscheme_program(prog_path, 1, script_args);\n" out)
+      (display "    close(fd);\n    Sscheme_deinit();\n    return status;\n}\n" out))))
 (write-main-c)
 
 ;; ── Stage 6: compile + link with cross-cc ──────────────────────────────────
 (printf "==> [6/6] compile + link with ~a~n" cross-cc)
-
 (define link-cmd
   (format
     (string-append
-      "~a -static -O2 "
-      "-I~a -I~a/usr/include "
-      "~a ~a "
+      "~a -static -O2 -I~a ~a "
       "-Wl,--start-group "
-      "~a/libkernel.a ~a/libz.a ~a/liblz4.a "
-      "~a/usr/lib/libssl.a ~a/usr/lib/libcrypto.a "
+      "~a ~a/libkernel.a ~a/libz.a ~a/liblz4.a "
       "-lpthread -lm -ldl "
-      "-Wl,--end-group "
-      "-o ~a")
-    cross-cc
-    cross-csv-dir musl-openssl-dir
-    main-c-path jerboa-ssl-shim-o
-    cross-csv-dir cross-csv-dir cross-csv-dir
-    musl-openssl-dir musl-openssl-dir
+      "-Wl,--end-group -o ~a")
+    cross-cc cross-csv-dir main-c-path
+    native-a cross-csv-dir cross-csv-dir cross-csv-dir
     output))
-
 (printf "    ~a~n" link-cmd)
 (unless (zero? (system link-cmd))
   (error 'build-jgl-cross "link failed"))
diff --git a/build-jgl-freebsd-cross.ss b/build-jgl-freebsd-cross.ss
deleted file mode 100644
index 2a81217..0000000
--- a/build-jgl-freebsd-cross.ss
+++ /dev/null
@@ -1,252 +0,0 @@
-#!chezscheme
-;;; build-jgl-freebsd-cross.ss — Cross-compile jgl from macOS to FreeBSD 14 amd64.
-;;;
-;;; Usage (from the repo root):
-;;;   JERBOA_HOME=$HOME/mine/jerboa scheme -q \
-;;;     --libdirs lib:$HOME/mine/jerboa/lib:$HOME/mine/jerboa-https/src:$HOME/mine/jerboa-ssl/src \
-;;;     --script build-jgl-freebsd-cross.ss
-;;;   (or: make cross-freebsd)
-;;;
-;;; Adapted from jerboa-aws/build-jaws-freebsd-cross.ss. Prerequisites:
-;;;   - $JERBOA_HOME/.chez-cross-ta6fb/   — cross-built Chez install (ta6fb)
-;;;   - $JERBOA_HOME/build/chez/xc-ta6fb/s/xpatch — host -> ta6fb emit-mode loader
-;;;   - x86_64-unknown-freebsd14-clang     — wrapper with sysroot + lld + libpath
-;;;   - ~/mine/jerboa-ssl/jerboa_ssl_shim-freebsd-amd64.o
-;;;   - ~/freebsd-sysroot/usr/lib/{libssl,libcrypto,...}.so (dynamic link)
-;;;
-;;; Produces: jgl-freebsd-amd64 (dynamic FreeBSD x86_64 ELF). Dynamic because
-;;; FreeBSD libc.so uses symbol versioning that libc.a can't satisfy; libssl/
-;;; libcrypto are resolved from FreeBSD base at run time.
-
-(import (chezscheme))
-
-;; ── Params ──────────────────────────────────────────────────────────────────
-(define jerboa-home
-  (or (getenv "JERBOA_HOME") "/Users/user/mine/jerboa"))
-
-(define cross-prefix (format "~a/.chez-cross-ta6fb" jerboa-home))
-(define xpatch       (format "~a/build/chez/xc-ta6fb/s/xpatch" jerboa-home))
-(define cross-cc     (or (getenv "CROSS_CC") "x86_64-unknown-freebsd14-clang"))
-
-(define output       "jgl-freebsd-amd64")
-(define entry-script "jgl.ss")
-
-(define jgl-repo (current-directory))
-(define jerboa-ssl-repo
-  (or (getenv "JERBOASSL_REPO") (format "~a/mine/jerboa-ssl" (getenv "HOME"))))
-(define jerboa-https-repo
-  (or (getenv "JERBOAHTTPS_REPO") (format "~a/mine/jerboa-https" (getenv "HOME"))))
-(define jerboa-ssl-shim-o
-  (or (getenv "JERBOA_SSL_SHIM_FREEBSD_O")
-      (format "~a/jerboa_ssl_shim-freebsd-amd64.o" jerboa-ssl-repo)))
-(define freebsd-sysroot
-  (or (getenv "FREEBSD_SYSROOT") (format "~a/freebsd-sysroot" (getenv "HOME"))))
-
-(define cross-csv-dir
-  (let ([lib (format "~a/lib" cross-prefix)])
-    (unless (file-directory? lib)
-      (error 'build-jgl-freebsd-cross "cross prefix lib dir missing" lib))
-    (let* ([entries (directory-list lib)]
-           [csvs    (filter (lambda (e)
-                              (and (>= (string-length e) 3)
-                                   (string=? (substring e 0 3) "csv")))
-                            entries)])
-      (when (null? csvs)
-        (error 'build-jgl-freebsd-cross "no csv* in cross lib" lib))
-      (format "~a/~a/ta6fb" lib (car csvs)))))
-
-(define (require-file p)
-  (unless (file-exists? p)
-    (error 'build-jgl-freebsd-cross "missing file" p)))
-
-(require-file xpatch)
-(require-file (format "~a/libkernel.a"  cross-csv-dir))
-(require-file (format "~a/scheme.h"     cross-csv-dir))
-(require-file (format "~a/petite.boot"  cross-csv-dir))
-(require-file (format "~a/scheme.boot"  cross-csv-dir))
-(require-file entry-script)
-(require-file jerboa-ssl-shim-o)
-(require-file (format "~a/usr/lib/libssl.so" freebsd-sysroot))
-
-(printf "==> build-jgl-freebsd-cross~n")
-(printf "    JERBOA_HOME:       ~a~n" jerboa-home)
-(printf "    cross csv-dir:     ~a~n" cross-csv-dir)
-(printf "    xpatch:            ~a~n" xpatch)
-(printf "    cross-cc:          ~a~n" cross-cc)
-(printf "    jerboa-ssl shim:     ~a~n" jerboa-ssl-shim-o)
-(printf "    freebsd sysroot:   ~a~n" freebsd-sysroot)
-(printf "    output:            ~a~n" output)
-(printf "~n")
-
-;; ── Stage 1: load xpatch (target=ta6fb emit mode) ──────────────────────────
-(define orig-libdirs (library-directories))
-(printf "==> [1/6] loading xpatch (compiler -> ta6fb emit mode)~n")
-(load xpatch)
-(library-directories
-  (append
-    (list (cons (format "~a/lib" jgl-repo)        (format "~a/lib" jgl-repo))
-          (cons (format "~a/lib" jerboa-home)     (format "~a/lib" jerboa-home))
-          (cons (format "~a/src" jerboa-https-repo) (format "~a/src" jerboa-https-repo))
-          (cons (format "~a/src" jerboa-ssl-repo)   (format "~a/src" jerboa-ssl-repo)))
-    orig-libdirs))
-
-(compile-imported-libraries #t)
-(generate-wpo-files #t)
-
-;; ── Stage 2: compile-program jgl.ss ─────────────────────────────────────────
-(printf "==> [2/6] compile-program ~a~n" entry-script)
-(compile-program entry-script)
-
-(define entry-wpo
-  (let ([n (string-length entry-script)])
-    (string-append (substring entry-script 0 (- n 3)) ".wpo")))
-
-;; ── Stage 3: compile-whole-program → wpo .so ───────────────────────────────
-(define wpo-output (string-append output ".wp.so"))
-(printf "==> [3/6] compile-whole-program ~a -> ~a~n" entry-wpo wpo-output)
-(compile-whole-program entry-wpo wpo-output #t)
-
-;; ── Stage 4: embed boot files + program as C arrays ────────────────────────
-(define (embed-as-c-array in-path var-name out-path)
-  (let* ([bv (call-with-port (open-file-input-port in-path) get-bytevector-all)]
-         [n (bytevector-length bv)])
-    (call-with-port (open-file-output-port out-path
-                       (file-options no-fail)
-                       (buffer-mode block)
-                       (native-transcoder))
-      (lambda (out)
-        (display (format "static const unsigned char ~a[] = {\n" var-name) out)
-        (let loop ([i 0])
-          (when (< i n)
-            (display (format "0x~2,'0x," (bytevector-u8-ref bv i)) out)
-            (when (= (mod (+ i 1) 16) 0) (newline out))
-            (loop (+ i 1))))
-        (when (positive? n) (newline out))
-        (display "};\n" out)
-        (display (format "static const unsigned int ~a_size = sizeof(~a);\n"
-                         var-name var-name)
-                 out)))
-    (printf "    embed ~a (~a bytes) -> ~a~n" in-path n out-path)))
-
-(printf "==> [4/6] embed boot files + program as C arrays~n")
-(embed-as-c-array (format "~a/petite.boot" cross-csv-dir) "petite_boot" "petite_boot.h")
-(embed-as-c-array (format "~a/scheme.boot" cross-csv-dir) "scheme_boot" "scheme_boot.h")
-(embed-as-c-array wpo-output                              "jgl_program" "jgl_program.h")
-
-;; ── Stage 5: generate main.c ───────────────────────────────────────────────
-(define main-c-path (string-append output "-main.c"))
-
-(define jerboa-ssl-symbols
-  '("jerboa_ssl_init"        "jerboa_ssl_cleanup"
-    "jerboa_ssl_connect"     "jerboa_ssl_write"      "jerboa_ssl_read"
-    "jerboa_ssl_read_all"    "jerboa_ssl_free_buf"   "jerboa_ssl_close"
-    "jerboa_ssl_memcpy"
-    "jerboa_ssl_server_ctx"  "jerboa_ssl_server_accept" "jerboa_ssl_server_ctx_free"
-    "jerboa_tcp_listen"      "jerboa_tcp_accept"
-    "jerboa_tcp_connect"     "jerboa_tcp_close"
-    "jerboa_tcp_read"        "jerboa_tcp_write"      "jerboa_tcp_read_all"
-    "jerboa_tcp_set_timeout"
-    "jerboa_tcp_conn_wrap"
-    "jerboa_conn_write"      "jerboa_conn_read"))
-
-(printf "==> [5/6] generate ~a (~a jerboa-ssl symbols)~n"
-        main-c-path (length jerboa-ssl-symbols))
-
-(define (write-main-c)
-  (call-with-port
-    (open-file-output-port main-c-path
-      (file-options no-fail) (buffer-mode block) (native-transcoder))
-    (lambda (out)
-      (display "/* Auto-generated by build-jgl-freebsd-cross.ss. Do not edit. */\n" out)
-      (display "#include <stdio.h>\n" out)
-      (display "#include <stdlib.h>\n" out)
-      (display "#include <string.h>\n" out)
-      (display "#include <unistd.h>\n" out)
-      (display "#include <fcntl.h>\n" out)
-      (display "#include <sys/types.h>\n" out)
-      (display "#include <sys/sysctl.h>\n" out)
-      (display "#include \"scheme.h\"\n" out)
-      (display "#include \"petite_boot.h\"\n" out)
-      (display "#include \"scheme_boot.h\"\n" out)
-      (display "#include \"jgl_program.h\"\n\n" out)
-
-      ;; FreeBSD: __errno_location alias (glibc/musl name) -> __error (FreeBSD).
-      (display "/* glibc/musl name for errno location -> FreeBSD __error. */\n" out)
-      (display "extern int *__error(void);\n" out)
-      (display "int *__errno_location(void) { return __error(); }\n\n" out)
-
-      ;; extern decls for jerboa-ssl symbols
-      (display "/* jerboa_ssl_shim.o exports — registered with Sforeign_symbol below. */\n" out)
-      (for-each
-        (lambda (sym) (display (format "extern void ~a(void);\n" sym) out))
-        jerboa-ssl-symbols)
-      (newline out)
-
-      (display "int main(int argc, char *argv[]) {\n" out)
-      (display "    /* Argv passthrough via env vars (matches the native jgl main). */\n" out)
-      (display "    char countbuf[32];\n" out)
-      (display "    snprintf(countbuf, sizeof(countbuf), \"%d\", argc - 1);\n" out)
-      (display "    setenv(\"JGL_ARGC\", countbuf, 1);\n" out)
-      (display "    for (int i = 1; i < argc; i++) {\n" out)
-      (display "        char name[32];\n" out)
-      (display "        snprintf(name, sizeof(name), \"JGL_ARG%d\", i - 1);\n" out)
-      (display "        setenv(name, argv[i], 1);\n" out)
-      (display "    }\n\n" out)
-
-      ;; FreeBSD: no /proc/self/fd/N (without fdescfs), write to a tmpfile.
-      (display "    /* FreeBSD has no /proc/self/fd/N (without fdescfs mounted), so write the\n" out)
-      (display "     * embedded program to a tmpfile that we unlink after Sscheme_program loads it. */\n" out)
-      (display "    char tmpl[] = \"/tmp/jgl-XXXXXX\";\n" out)
-      (display "    int fd = mkstemp(tmpl);\n" out)
-      (display "    if (fd < 0) { perror(\"mkstemp\"); return 1; }\n" out)
-      (display "    if (write(fd, jgl_program, jgl_program_size) != (ssize_t)jgl_program_size) {\n" out)
-      (display "        perror(\"write tmpfile\"); close(fd); unlink(tmpl); return 1;\n" out)
-      (display "    }\n" out)
-      (display "    fsync(fd);\n\n" out)
-
-      (display "    Sscheme_init(NULL);\n" out)
-      (display "    Sregister_boot_file_bytes(\"petite\", (void*)petite_boot, petite_boot_size);\n" out)
-      (display "    Sregister_boot_file_bytes(\"scheme\", (void*)scheme_boot, scheme_boot_size);\n\n" out)
-
-      (display "    /* Register jerboa_ssl_shim symbols so the WPO resolves them at runtime. */\n" out)
-      (for-each
-        (lambda (sym)
-          (display (format "    Sforeign_symbol(\"~a\", (void*)~a);\n" sym sym) out))
-        jerboa-ssl-symbols)
-      (newline out)
-
-      (display "    Sbuild_heap(NULL, NULL);\n" out)
-      (display "    const char *script_args[] = { argv[0] };\n" out)
-      (display "    int status = Sscheme_program(tmpl, 1, script_args);\n\n" out)
-      (display "    close(fd);\n" out)
-      (display "    unlink(tmpl);\n" out)
-      (display "    Sscheme_deinit();\n" out)
-      (display "    return status;\n" out)
-      (display "}\n" out))))
-(write-main-c)
-
-;; ── Stage 6: compile + link with cross-cc ──────────────────────────────────
-;; FreeBSD dynamic link: libssl/libcrypto from base, no -static (libc symbol
-;; versioning), libutil for openpty.
-(printf "==> [6/6] compile + link with ~a~n" cross-cc)
-
-(define link-cmd
-  (format
-    (string-append
-      "~a -O2 -Wl,--export-dynamic "
-      "-I~a "
-      "~a ~a "
-      "~a/libkernel.a ~a/libz.a ~a/liblz4.a "
-      "-lssl -lcrypto -lpthread -lm -lutil "
-      "-o ~a")
-    cross-cc
-    cross-csv-dir
-    main-c-path jerboa-ssl-shim-o
-    cross-csv-dir cross-csv-dir cross-csv-dir
-    output))
-
-(printf "    ~a~n" link-cmd)
-(unless (zero? (system link-cmd))
-  (error 'build-jgl-freebsd-cross "link failed"))
-
-(printf "~n==> done: ~a~n" output)