build: use jerbuild for native jcode builds
ober
7330c2fed0f64c20a375a00a1426f761bca53ee6
--- a/.build.yml +++ b/.build.yml @@ -5,11 +5,7 @@ packages: - uuid-dev - libz-dev - liblz4-dev - - libpcre2-dev - - libsqlite3-dev - - libssl-dev - libx11-dev - - pkg-config - git - curl - unzip @@ -26,27 +22,20 @@ tasks: # install one via rustup and persist it onto PATH for every later task. curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh -s -- -y --profile minimal --default-toolchain stable echo 'source "$HOME/.cargo/env"' >> ~/.buildenv - - bootstrap-chez: | + - install-jerbuild: | cd jerboa - # Build the vendored Chez Scheme locally into ~/jerboa/.chez. - # `make chez` is the documented bootstrap entry point. - make chez - - build-jerboa: | - cd jerboa - # Build the Rust native lib FIRST. The stdlib libraries jcode imports - # bind its FFI symbols at visit time, so libjerboa_native must already be - # in lib/ before anything importing them is compiled. - make native - make build + make jerboa + make install PREFIX=$HOME/.local + echo 'export PATH="$HOME/.local/bin:$PATH"' >> ~/.buildenv - vendor-code: | cd jerboa-code mkdir -p vendor - [ -d vendor/chez-sqlite ] || git clone --depth 1 https://git.sr.ht/~lisp/chez-sqlite vendor/chez-sqlite + [ -d vendor/jerboa-sqlite ] || git clone --depth 1 https://git.sr.ht/~lisp/jerboa-sqlite vendor/jerboa-sqlite [ -d vendor/termbox2 ] || git clone --depth 1 https://github.com/termbox/termbox2.git vendor/termbox2 [ -d vendor/jerboa-websearch ] || git clone --depth 1 https://git.sr.ht/~lisp/jerboa-websearch vendor/jerboa-websearch - build-code: | cd jerboa-code - JERBOA_HOME=$HOME/jerboa make build + env -u JERBOA_HOME make build - test-code: | cd jerboa-code - JERBOA_HOME=$HOME/jerboa make test + env -u JERBOA_HOME make test --- a/.gitignore +++ b/.gitignore @@ -11,6 +11,7 @@ jcode.json # Generated Scheme libraries (built from src/**/*.ss by jerbuild) /lib/ +/support/sqlite-bundled/target/ /jcode_tui_shim.dylib /jcode_tui_shim.so --- a/.jerbuild +++ b/.jerbuild @@ -3,20 +3,18 @@ ;; jerbuild bundles Chez Scheme + the jerboa stdlib, so NO jerboa source ;; checkout or external Chez is required. The only external input is the native ;; Rust lib (libjerboa_native), built from vendor/jerboa-native-rs with the -;; features jcode needs (tls + sqlite + crypto). +;; features jcode needs (tls + crypto). SQLite comes from jerboa-sqlite's C +;; shim so the binary does not link duplicate jerboa_sqlite_* symbols. ;; -;; Static FFI needs NO source patching: chez-sqlite.sls falls through to (void) +;; Static FFI needs NO source patching: jerboa-sqlite.sls falls through to (void) ;; and tui-ffi.ss honors JERBOA_STATIC=1 (set by support/jcode-main.c), so the ;; linked-in shim symbols resolve via the registered FFI symbols below. (entry "main-binary.ss") (output "jcode") -(requires "cargo" "cc" "sqlite3 headers/libs" "vendor/jerboa-native-rs") -(notes "jerboa-native-rs is built with no default features and tls,sqlite,crypto only. DuckDB is intentionally not required.") - ;; do-binary-build auto-appends the bundled stdlib; list only project + vendor. (libdirs "lib" - "vendor/chez-sqlite/src" + "vendor/jerboa-sqlite/lib" "vendor/jerboa-websearch/src") ;; Symbols statically registered via Sforeign_symbol (sqlite shim, termbox TUI @@ -26,15 +24,18 @@ ;; Stock jerbuild main.c + setenv(JERBOA_STATIC=1); see the file's header. (main-c "support/jcode-main.c") -;; C shims compiled into the binary. sqlite3.h is provided by the macOS SDK / -;; system; add an -I here if a host needs an explicit path. +;; C shims compiled into the binary. SQLite comes from the Cargo-built bundled +;; archive below, with support/sqlite3.h providing the small C API surface used +;; by the shim. (extra-sources - "vendor/chez-sqlite/chez_sqlite_shim.c" + ("vendor/jerboa-sqlite/jerboa_sqlite_shim.c" cflags: "-Isupport") ("src/jcode/ui/jcode_tui_shim.c" cflags: "-DTB_OPT_ATTR_W=32 -Ivendor/termbox2")) -;; jerboa-native (Rust): tls + sqlite + crypto only (no duckdb/pcap/postgres). jerbuild +(extra-archives "support/sqlite-bundled/target/release/libjcode_sqlite_bundled.a") + +;; jerboa-native (Rust): tls + crypto only (no sqlite/duckdb/pcap/postgres). jerbuild ;; runs cargo and links the resulting libjerboa_native.a. (rust-crates ("vendor/jerboa-native-rs/Cargo.toml" - features: "tls,sqlite,crypto" + features: "tls,crypto" no-default-features: #t)) new file mode 100644 --- /dev/null +++ b/.jerbuild.freebsd-amd64 @@ -0,0 +1,36 @@ +;; jerbuild build config for jerboa-code (jcode) -- native FreeBSD amd64. +;; +;; Build on a FreeBSD amd64 host with: +;; jerbuild build --config .jerbuild.freebsd-amd64 +;; +;; This uses only installed jerbuild, cc, cargo, and project/vendor deps. + +(entry "main-binary.ss") +(output "jcode-freebsd-amd64") + +(cc "cc") + +;; FreeBSD has dlopen in libc. -lutil covers openpty, termcap backs Chez's +;; expeditor, and GNU libiconv is installed under /usr/local/lib. +(os-libs "-lm -lpthread -lutil -ltermcap -L/usr/local/lib -liconv") + +(libdirs "lib" + "vendor/jerboa-sqlite/lib" + "vendor/jerboa-websearch/src") + +(ffi-symbols "support/ffi-symbols.list") + +(main-c "support/jcode-main.c") + +(extra-sources + ("vendor/jerboa-sqlite/jerboa_sqlite_shim.c" cflags: "-Isupport") + ("src/jcode/ui/jcode_tui_shim.c" cflags: "-DTB_OPT_ATTR_W=32 -Ivendor/termbox2")) + +(extra-archives "support/sqlite-bundled/target/release/libjcode_sqlite_bundled.a") + +(extra-ldflags "-Wl,--export-dynamic") + +(rust-crates + ("vendor/jerboa-native-rs/Cargo.toml" + features: "tls,crypto" + no-default-features: #t)) new file mode 100644 --- /dev/null +++ b/.jerbuild.linux-amd64 @@ -0,0 +1,34 @@ +;; jerbuild build config for jerboa-code (jcode) -- native Linux amd64. +;; +;; Build on a Linux amd64 host with: +;; jerbuild build --config .jerbuild.linux-amd64 +;; +;; This uses only installed jerbuild, cc, cargo, and project/vendor deps. + +(entry "main-binary.ss") +(output "jcode-linux-amd64") + +(cc "cc") + +(os-libs "-lm -ldl -lpthread -luuid -lncurses -lstdc++") + +(libdirs "lib" + "vendor/jerboa-sqlite/lib" + "vendor/jerboa-websearch/src") + +(ffi-symbols "support/ffi-symbols.list") + +(main-c "support/jcode-main.c") + +(extra-sources + ("vendor/jerboa-sqlite/jerboa_sqlite_shim.c" cflags: "-Isupport") + ("src/jcode/ui/jcode_tui_shim.c" cflags: "-DTB_OPT_ATTR_W=32 -Ivendor/termbox2")) + +(extra-archives "support/sqlite-bundled/target/release/libjcode_sqlite_bundled.a") + +(extra-ldflags "-Wl,--export-dynamic") + +(rust-crates + ("vendor/jerboa-native-rs/Cargo.toml" + features: "tls,crypto" + no-default-features: #t)) new file mode 100644 --- /dev/null +++ b/.jerbuild.linux-arm64 @@ -0,0 +1,34 @@ +;; jerbuild build config for jerboa-code (jcode) -- native Linux arm64. +;; +;; Build on a Linux arm64/aarch64 host with: +;; jerbuild build --config .jerbuild.linux-arm64 +;; +;; This uses only installed jerbuild, cc, cargo, and project/vendor deps. + +(entry "main-binary.ss") +(output "jcode-linux-arm64") + +(cc "cc") + +(os-libs "-lm -ldl -lpthread -luuid -lncurses -lstdc++") + +(libdirs "lib" + "vendor/jerboa-sqlite/lib" + "vendor/jerboa-websearch/src") + +(ffi-symbols "support/ffi-symbols.list") + +(main-c "support/jcode-main.c") + +(extra-sources + ("vendor/jerboa-sqlite/jerboa_sqlite_shim.c" cflags: "-Isupport") + ("src/jcode/ui/jcode_tui_shim.c" cflags: "-DTB_OPT_ATTR_W=32 -Ivendor/termbox2")) + +(extra-archives "support/sqlite-bundled/target/release/libjcode_sqlite_bundled.a") + +(extra-ldflags "-Wl,--export-dynamic") + +(rust-crates + ("vendor/jerboa-native-rs/Cargo.toml" + features: "tls,crypto" + no-default-features: #t)) deleted file mode 100644 --- a/Dockerfile +++ /dev/null @@ -1,59 +0,0 @@ -# Dockerfile — Build jcode-musl using the jerboa21/jerboa base image -# -# Produces a fully static binary with zero runtime dependencies. -# No Chez Scheme or Jerboa installation needed on the target host. -# -# The base image (jerboa21/jerboa) provides stock Chez, musl Chez, -# jerboa libs, and all build dependencies pre-installed. -# -# Usage: -# docker build -t jcode-builder . -# docker run --rm jcode-builder > jcode-musl && chmod +x jcode-musl -# -# Or extract via docker cp: -# docker build -t jcode-builder . -# id=$(docker create jcode-builder) -# docker cp $id:/out/jcode-musl ./jcode-musl -# docker rm $id - -FROM jerboa21/jerboa AS builder - -ARG CACHE_BUST - -# ── Overlay the host's ~/mine/jerboa over the base image's bundled copy ───── -# The base image's /build/mine/jerboa is a snapshot and lags reality as soon -# as a new module lands upstream (e.g. (std os errno) added on 2026-05-13). -# Without this overlay the build fails with "library (std os errno) not -# found" every time jcode source references a fresh jerboa module. -# -# Source: --build-context host-jerboa=<path> from the Makefile docker target. -# We delete any compiled .so/.wpo from the overlay so the freshly-copied -# sources get recompiled against the container's Chez (a host-built .so -# from a different libc/version would be wrong inside the container). -COPY --from=host-jerboa . /build/mine/jerboa-host-overlay -RUN find /build/mine/jerboa-host-overlay \( -name '*.so' -o -name '*.wpo' \) -delete 2>/dev/null; \ - rm -rf /build/mine/jerboa && \ - mv /build/mine/jerboa-host-overlay /build/mine/jerboa && \ - find /build/mine/jerboa/lib \( -name '*.so' -o -name '*.wpo' \) -delete 2>/dev/null; true - -# ── Copy jcode source ──────────────────────────────────────────────────────── -COPY . /build/mine/jerboa-code - -# ── Build jcode-musl ───────────────────────────────────────────────────────── -WORKDIR /build/mine/jerboa-code -RUN JERBOA_HOME=/build/mine/jerboa make linux-local - -# ── Verify ─────────────────────────────────────────────────────────────────── -RUN echo "--- Binary info ---" && \ - ls -lh jcode-musl && \ - file jcode-musl && \ - echo "--- Hardening checks ---" && \ - { file jcode-musl | grep -qE 'stripped|no section header' && echo " PASS: stripped" || echo " WARN: not stripped"; } && \ - echo "--- Path leak check ---" && \ - count=$(strings jcode-musl | grep -c '/home/' || true) && \ - { [ "$count" -gt 0 ] && echo " WARNING: home paths found ($count)" || echo " PASS: no home path leaks"; } - -# ── Output ─────────────────────────────────────────────────────────────────── -FROM ubuntu:24.04 -COPY --from=builder /build/mine/jerboa-code/jcode-musl /out/jcode-musl -CMD ["cat", "/out/jcode-musl"] --- a/Makefile +++ b/Makefile @@ -10,45 +10,43 @@ ifeq ($(JH),) $(error jerbuild not found on PATH (or '$(JERBUILD) --jerboa-home' failed). Install jerbuild, or set JERBUILD=/path/to/jerbuild) endif -# JERBOA_HOME / SCHEME are used ONLY by the cross-compile targets -# (linux*/freebsd*/android) and the legacy `binary-legacy` fallback — the host -# dev loop and `make binary` no longer touch them. -JERBOA_HOME ?= $(HOME)/mine/jerboa -SCHEME ?= $(JERBOA_HOME)/.chez/bin/scheme -FREEBSD_AMD64_CC ?= $(JERBOA_HOME)/support/cross-cc-freebsd-amd64 - -LIBDIRS := --libdirs ./lib:vendor/chez-sqlite/src:vendor/jerboa-websearch/src:$(JH)/lib +LIBDIRS := --libdirs ./lib:vendor/jerboa-sqlite/lib:vendor/jerboa-websearch/src:$(JH)/lib JEXEC := $(JERBUILD) exec $(LIBDIRS) # Library paths for FFI shared objects (macOS: dylib, Linux: so). The native # Rust lib now lives in ./lib (dropped by the native-rs target), matching the # (std crypto native-rust) loader's CWD-relative "lib/" fallback. -SQLITE_LIB_DIR := $(shell brew --prefix sqlite 2>/dev/null)/lib -SHIM_DIR := $(CURDIR)/vendor/chez-sqlite +SHIM_DIR := $(CURDIR)/vendor/jerboa-sqlite +SQLITE_STAGE := vendor/jerboa-sqlite/.jcode-src +SQLITE_BUNDLED_DIR := support/sqlite-bundled +SQLITE_BUNDLED_A := $(SQLITE_BUNDLED_DIR)/target/release/libjcode_sqlite_bundled.a TUI_SHIM_DIR := $(CURDIR)/vendor/termbox2 NATIVE_LIB_DIR := $(CURDIR)/lib -LDPATH := $(SHIM_DIR):$(TUI_SHIM_DIR):$(SQLITE_LIB_DIR):$(NATIVE_LIB_DIR) +LDPATH := $(SHIM_DIR):$(TUI_SHIM_DIR):$(NATIVE_LIB_DIR) # Native Rust lib (vendored crate, built with cargo). Only the features jcode # uses — tls + crypto; no duckdb/pcap/postgres. NATIVE_DIR := vendor/jerboa-native-rs NATIVE_FEATURES ?= tls,crypto +comma := , +NATIVE_FEATURES_TAG := $(subst $(comma),-,$(NATIVE_FEATURES)) NATIVE_A := $(NATIVE_DIR)/target/release/libjerboa_native.a NATIVE_DYLIB := $(NATIVE_DIR)/target/release/libjerboa_native.dylib NATIVE_SO := $(NATIVE_DIR)/target/release/libjerboa_native.so +NATIVE_SENTINEL := $(NATIVE_DIR)/target/release/.built-with-$(NATIVE_FEATURES_TAG) # Per-OS link flags handed to `jerbuild build --os-libs`. jerbuild appends # these after the Chez kernel + our archives when linking the binary. UNAME_S := $(shell uname -s) ifeq ($(UNAME_S),Darwin) -JCODE_OS_LIBS := -lm -lpthread -lncurses -liconv -lc++ -L$(SQLITE_LIB_DIR) -lsqlite3 -framework Security -framework CoreFoundation +JCODE_OS_LIBS := -lm -lpthread -lncurses -liconv -lc++ -framework Security -framework CoreFoundation else ifeq ($(UNAME_S),FreeBSD) -JCODE_OS_LIBS := -lm -lpthread -lncurses -L/usr/local/lib -liconv -lsqlite3 +JCODE_OS_LIBS := -lm -lpthread -lutil -lncurses -L/usr/local/lib -liconv else -JCODE_OS_LIBS := -lm -ldl -lpthread -luuid -lncurses -lsqlite3 -lstdc++ +JCODE_OS_LIBS := -lm -ldl -lpthread -luuid -lncurses -lstdc++ endif -.PHONY: all help build gen run test test-providers clean repl binary binary-legacy install tui-shim run-tui native-rs jcode-musl linux linux-amd64 linux-arm64 jcode-linux-amd64 linux-docker linux-check linux-local docker test-linux test-linux-amd64 purge-stale sqlite-shim android android-clean vendor-deps vendor-clean +.PHONY: all help build gen run test test-providers clean repl binary install tui-shim run-tui native-rs sqlite-bundled linux linux-amd64 linux-arm64 jcode-linux-amd64 jcode-linux-arm64 jcode-linux-native jcode-linux-arm64-native freebsd freebsd-amd64 jcode-freebsd-amd64 jcode-freebsd-native purge-stale sqlite-shim sqlite-lib android android-clean vendor-deps vendor-clean all: help @@ -62,19 +60,17 @@ help: @echo " repl Open a bare Scheme REPL with project libdirs" @echo " gen Transpile src/ → lib/ + rebuild sqlite shim (jerbuild)" @echo " native-rs Build vendored libjerboa_native (cargo, tls+crypto)" + @echo " sqlite-bundled Build bundled SQLite archive via cargo" @echo " binary Build native binary via 'jerbuild build' (.jerbuild)" - @echo " binary-legacy Fallback binary via build-binary.ss (needs jerboa checkout)" @echo " install Install binary to ~/.local/bin" - @echo " linux Build Linux x86_64 static binary (cross-compile from this host)" - @echo " linux-amd64 Cross-compile static jcode-linux-amd64 (default)" - @echo " linux-arm64 Cross-compile static jcode-linux-arm64" - @echo " linux-docker Build static musl binary via Docker (slower; canonical)" - @echo " linux-local Build static musl binary on host (Linux only)" - @echo " linux-check Fast drift check for musl build path" - @echo " test-linux Smoke-test the cross-compiled binary under podman/qemu" + @echo " linux Build Linux x86_64 binary with jerbuild (run on Linux)" + @echo " linux-amd64 Build native Linux x86_64 jcode-linux-amd64 with jerbuild" + @echo " linux-arm64 Build native Linux arm64 jcode-linux-arm64 with jerbuild" + @echo " freebsd Build FreeBSD amd64 binary with jerbuild (run on FreeBSD)" @echo " clean Remove compiled artifacts and binaries" @echo " purge-stale Remove stale .so/.wpo files" - @echo " sqlite-shim Rebuild chez_sqlite_shim.so" + @echo " sqlite-shim Rebuild jerboa_sqlite_shim.so" + @echo " sqlite-lib Transpile vendor/jerboa-sqlite src/ → lib/" @echo " tui-shim Rebuild jcode_tui_shim" @echo " android Build Android APK in Termux (android/build/*.apk)" @echo " android-clean Remove android/build/" @@ -85,7 +81,7 @@ help: # to the class of bug where a stale .so silently linked against an old # shim causes a runtime "no entry for X" foreign-procedure error. # -# Always also clear the prebuilt vendor/chez-sqlite artifacts — they pin +# Always also clear the prebuilt vendor/jerboa-sqlite artifacts — they pin # absolute paths to the shim and are cheap to recompile. purge-stale: @find lib -name "*.so" -o -name "*.wpo" 2>/dev/null | while read f; do \ @@ -105,21 +101,40 @@ purge-stale: break; \ fi; \ done - @rm -f vendor/chez-sqlite/src/chez-sqlite.so vendor/chez-sqlite/src/chez-sqlite.wpo + @rm -f vendor/jerboa-sqlite/lib/jerboa-sqlite.so vendor/jerboa-sqlite/lib/jerboa-sqlite.wpo -# ── chez-sqlite shim build ────────────────────────────────────────────────── +# ── jerboa-sqlite shim build ────────────────────────────────────────────────── # Rebuild the FFI shim if its C source is newer than the .so. This catches -# the case where vendor/chez-sqlite is updated but the .so isn't refreshed. -sqlite-shim: vendor/chez-sqlite - @if [ ! -f vendor/chez-sqlite/chez_sqlite_shim.so ] || \ - [ vendor/chez-sqlite/chez_sqlite_shim.c -nt vendor/chez-sqlite/chez_sqlite_shim.so ]; then \ - echo "=== Rebuilding chez_sqlite_shim.so ==="; \ +# the case where vendor/jerboa-sqlite is updated but the .so isn't refreshed. +sqlite-bundled: + @command -v cargo >/dev/null 2>&1 || { \ + echo "ERROR: cargo not found on PATH. Install rustup from rustup.rs"; exit 1; } + @if [ ! -f "$(SQLITE_BUNDLED_A)" ] || \ + [ "$(SQLITE_BUNDLED_DIR)/Cargo.toml" -nt "$(SQLITE_BUNDLED_A)" ] || \ + [ -n "$$(find $(SQLITE_BUNDLED_DIR)/src -name '*.rs' -newer $(SQLITE_BUNDLED_A) 2>/dev/null)" ]; then \ + echo "=== Building bundled SQLite archive ==="; \ + ( cd $(SQLITE_BUNDLED_DIR) && cargo build --release ); \ + fi + +sqlite-shim: vendor/jerboa-sqlite sqlite-bundled + @if [ ! -f vendor/jerboa-sqlite/jerboa_sqlite_shim.so ] || \ + [ vendor/jerboa-sqlite/jerboa_sqlite_shim.c -nt vendor/jerboa-sqlite/jerboa_sqlite_shim.so ] || \ + [ support/sqlite3.h -nt vendor/jerboa-sqlite/jerboa_sqlite_shim.so ] || \ + [ "$(SQLITE_BUNDLED_A)" -nt vendor/jerboa-sqlite/jerboa_sqlite_shim.so ]; then \ + echo "=== Rebuilding jerboa_sqlite_shim.so ==="; \ cc -shared -fPIC -O2 \ - -I$(SQLITE_LIB_DIR)/../include -L$(SQLITE_LIB_DIR) \ - -o vendor/chez-sqlite/chez_sqlite_shim.so \ - vendor/chez-sqlite/chez_sqlite_shim.c -lsqlite3; \ + -Isupport \ + -o vendor/jerboa-sqlite/jerboa_sqlite_shim.so \ + vendor/jerboa-sqlite/jerboa_sqlite_shim.c $(SQLITE_BUNDLED_A); \ fi +sqlite-lib: vendor/jerboa-sqlite + @rm -rf $(SQLITE_STAGE) + @mkdir -p $(SQLITE_STAGE) + @sed '/^(import (jerboa prelude))$$/d' \ + vendor/jerboa-sqlite/src/jerboa-sqlite.ss > $(SQLITE_STAGE)/jerboa-sqlite.ss + $(JERBUILD) transpile $(SQLITE_STAGE) vendor/jerboa-sqlite/lib --force + # ── libjerboa_native (Rust FFI) ───────────────────────────────────────────── # secrets.ss + std/net/request + std/regex etc. all bind FFI symbols from # libjerboa_native at library load time, so the shared lib must exist in @@ -135,9 +150,12 @@ native-rs: $(NATIVE_DIR) @command -v cargo >/dev/null 2>&1 || { \ echo "ERROR: cargo not found on PATH. Install rustup from rustup.rs"; exit 1; } @if [ ! -f "$(NATIVE_A)" ] || \ + [ ! -f "$(NATIVE_SENTINEL)" ] || \ [ -n "$$(find $(NATIVE_DIR)/src -name '*.rs' -newer $(NATIVE_A) 2>/dev/null)" ]; then \ echo "=== Building libjerboa_native (features: $(NATIVE_FEATURES)) ==="; \ - ( cd $(NATIVE_DIR) && cargo build --release --features $(NATIVE_FEATURES) ); \ + ( cd $(NATIVE_DIR) && cargo build --release --no-default-features --features $(NATIVE_FEATURES) ); \ + rm -f $(NATIVE_DIR)/target/release/.built-with-*; \ + touch "$(NATIVE_SENTINEL)"; \ fi @mkdir -p lib @# The dev loop loads a shared object; the binary links the .a (jerbuild @@ -155,13 +173,13 @@ native-rs: $(NATIVE_DIR) # we do NOT use git submodules — every target that needs vendor/<x> depends on # vendor-deps so a fresh checkout populates itself. -vendor-deps: vendor/chez-sqlite vendor/termbox2 vendor/jerboa-websearch +vendor-deps: vendor/jerboa-sqlite vendor/termbox2 vendor/jerboa-websearch -vendor/chez-sqlite: +vendor/jerboa-sqlite: @mkdir -p vendor - @echo "=== Cloning chez-sqlite into vendor/ ===" - @git clone --depth 1 git@git.sr.ht:~lisp/chez-sqlite vendor/chez-sqlite - @rm -f vendor/chez-sqlite/chez_sqlite_shim.so + @echo "=== Cloning jerboa-sqlite into vendor/ ===" + @git clone --depth 1 https://git.sr.ht/~lisp/jerboa-sqlite vendor/jerboa-sqlite + @rm -f vendor/jerboa-sqlite/jerboa_sqlite_shim.so vendor/termbox2: @mkdir -p vendor @@ -171,7 +189,7 @@ vendor/termbox2: vendor/jerboa-websearch: @mkdir -p vendor @echo "=== Cloning jerboa-websearch into vendor/ ===" - @git clone --depth 1 git@git.sr.ht:~lisp/jerboa-websearch vendor/jerboa-websearch + @git clone --depth 1 https://git.sr.ht/~lisp/jerboa-websearch vendor/jerboa-websearch # Sparse-clone just the jerboa-native-rs crate out of the jerboa monorepo. # Depended on only by native-rs (not vendor-deps), so cross targets — which @@ -179,7 +197,7 @@ vendor/jerboa-websearch: $(NATIVE_DIR): @mkdir -p vendor @echo "=== Sparse-cloning jerboa-native-rs from the jerboa monorepo ===" - @git clone --depth 1 --filter=blob:none --sparse git@git.sr.ht:~lisp/jerboa vendor/.jerboa-monorepo + @git clone --depth 1 --filter=blob:none --sparse https://git.sr.ht/~lisp/jerboa vendor/.jerboa-monorepo @git -C vendor/.jerboa-monorepo sparse-checkout set jerboa-native-rs @mv vendor/.jerboa-monorepo/jerboa-native-rs $(NATIVE_DIR) @rm -rf vendor/.jerboa-monorepo @@ -187,12 +205,12 @@ $(NATIVE_DIR): vendor-clean: rm -rf vendor -gen: vendor-deps purge-stale sqlite-shim +gen: vendor-deps purge-stale sqlite-shim sqlite-lib $(JERBUILD) transpile src lib build: gen native-rs DYLD_LIBRARY_PATH=$(LDPATH) LD_LIBRARY_PATH=$(LDPATH) \ - $(JERBUILD) compile $(LIBDIRS) main.ss < /dev/null + $(JERBUILD) compile $(LIBDIRS) support/build-check.ss < /dev/null run: native-rs DYLD_LIBRARY_PATH=$(LDPATH) LD_LIBRARY_PATH=$(LDPATH) \ @@ -232,18 +250,7 @@ test-providers: build # .a, and links it all. Per-OS link flags come from --os-libs. binary: gen native-rs DYLD_LIBRARY_PATH=$(LDPATH) LD_LIBRARY_PATH=$(LDPATH) \ - $(JERBUILD) build --os-libs "$(JCODE_OS_LIBS)" - cp vendor/termbox2/jcode_tui_shim.dylib ./jcode_tui_shim.dylib 2>/dev/null || true - cp vendor/termbox2/jcode_tui_shim.so ./jcode_tui_shim.so 2>/dev/null || true - -# Fallback: the hand-rolled WPO build. Requires a full ~/mine/jerboa checkout -# with a locally-built Chez ($(SCHEME)) and `make -C $(JERBOA_HOME) native` -# already run. Kept until `binary` is proven across hosts, then removed. -binary-legacy: gen tui-shim - JERBOA_HOME=$(JERBOA_HOME) \ - DYLD_LIBRARY_PATH=$(LDPATH) LD_LIBRARY_PATH=$(LDPATH) \ - $(SCHEME) -q --libdirs $(JERBOA_HOME)/lib:./lib:vendor/chez-sqlite/src:vendor/jerboa-websearch/src \ - --script build-binary.ss + $(JERBUILD) build --config .jerbuild --os-libs "$(JCODE_OS_LIBS)" cp vendor/termbox2/jcode_tui_shim.dylib ./jcode_tui_shim.dylib 2>/dev/null || true cp vendor/termbox2/jcode_tui_shim.so ./jcode_tui_shim.so 2>/dev/null || true @@ -251,164 +258,78 @@ install: binary mkdir -p $(HOME)/.local/bin cp jcode $(HOME)/.local/bin/jcode cp vendor/termbox2/jcode_tui_shim.dylib $(HOME)/.local/bin/jcode_tui_shim.dylib 2>/dev/null || true - cp vendor/chez-sqlite/chez_sqlite_shim.so $(PREFIX)/lib/chez_sqlite_shim.so 2>/dev/null || true @if [ "$$(uname)" = "Darwin" ]; then \ codesign --force --sign - $(HOME)/.local/bin/jcode; \ [ -f $(HOME)/.local/bin/jcode_tui_shim.dylib ] && codesign --force --sign - $(HOME)/.local/bin/jcode_tui_shim.dylib || true; \ fi @echo "Installed to ~/.local/bin/jcode" -# `make linux` now defaults to the fast cross-compile path. Use `make -# linux-docker` for the canonical Docker build (reproducible, slower). +# `make linux` builds on a Linux amd64 host through installed jerbuild. linux: linux-amd64 -linux-docker: linux-check docker -# ── Fast local drift check for the musl build path ───────────────────────── -# Runs compile-program on main-binary.ss with the same flags the musl build -# uses, but skips sed patching, the C compile, and the linker. Catches drift -# (new imports, removed stdlib exports, broken except clauses) on the dev's -# laptop in ~10 seconds, before burning 5+ minutes in Docker. -# -# `linux` and `linux-local` both depend on this target so they fail fast. +# ─── Linux amd64 binary ───────────────────────────────────────────────────── +# Native Linux build through installed jerbuild. Requires cc and cargo. + +linux-amd64: + @case "$$(uname -s)-$$(uname -m)" in \ + Linux-x86_64|Linux-amd64) ;; \ + *) echo "ERROR: linux-amd64 is a native jerbuild target; run it on Linux amd64" >&2; exit 1 ;; \ + esac + @$(MAKE) jcode-linux-native + +linux-arm64: + @case "$$(uname -s)-$$(uname -m)" in \ + Linux-aarch64|Linux-arm64) ;; \ + *) echo "ERROR: linux-arm64 is a native jerbuild target; run it on Linux arm64/aarch64" >&2; exit 1 ;; \ + esac + @$(MAKE) jcode-linux-arm64-native + +jcode-linux-native: gen $(NATIVE_DIR) + @case "$$(uname -s)-$$(uname -m)" in \ + Linux-x86_64|Linux-amd64) ;; \ + *) echo "ERROR: .jerbuild.linux-amd64 must run on Linux amd64" >&2; exit 1 ;; \ + esac + @echo "=== Building native Linux amd64 jcode with jerbuild ===" + $(JERBUILD) build --config .jerbuild.linux-amd64 + @ls -lh jcode-linux-amd64 + @file jcode-linux-amd64 -linux-check: gen - @echo "=== Running linux-check (fast musl-build drift check) ===" - DYLD_LIBRARY_PATH=$(LDPATH) LD_LIBRARY_PATH=$(LDPATH) \ - $(SCHEME) -q --libdirs "$(XC_LIBDIRS)" --script linux-check.ss - -# ── Docker build (canonical static binary, zero runtime deps) ─────────────── -# Use `make linux` to build in Docker (canonical, reproducible). -# Use `make linux-local` to build directly on the host (requires -# musl-gcc and a musl-built Chez at ~/chez-musl or JERBOA_MUSL_CHEZ_PREFIX). - -docker: - @echo "=== Building jcode-musl in Docker ===" - @# Pass the host's ~/mine/jerboa as an additional build context. The base - @# image's bundled jerboa lags reality; without this overlay the build - @# breaks every time jcode source references a jerboa module added since - @# the base image was last rebuilt (e.g. (std os errno) added 2026-05-13). - DOCKER_BUILDKIT=1 docker build \ - --platform linux/amd64 \ - --build-arg CACHE_BUST=$$(date +%s) \ - --build-context host-jerboa=$(JERBOA_HOME) \ - -t jcode-builder . - @id=$$(docker create --platform linux/amd64 jcode-builder) && \ - docker cp $$id:/out/jcode-musl ./jcode-musl && \ - docker rm $$id >/dev/null && \ - chmod +x jcode-musl - @echo "" - @ls -lh jcode-musl - @file jcode-musl - -# ─── musl Static Binary ────────────────────────────────────────────────────── -# Build a fully static jcode binary using musl libc. -# Requires: musl-gcc, Chez Scheme built with musl (~/chez-musl), -# jerboa-native-rs built for x86_64-unknown-linux-musl. - -linux-local: linux-check - @echo "=== Building static jcode with musl ===" - JERBOA_HOME=$(JERBOA_HOME) ./build-jcode-musl.sh - -# jcode-musl routes through Docker by default. The native `linux-local` -# path depends on the host's Chez (musl + glibc) staying in lock-step -# with the source — this kept breaking every time the host scheme moved -# or a stale ~/chez-musl was around. The Docker path uses jerboa21/jerboa -# which ships pre-built host + musl Chez and the full Rust toolchain, so -# the build is reproducible and survives host drift. Use `make linux-local` -# if you specifically want a native build. -jcode-musl: docker - -# ─── Cross-compile (macOS / FreeBSD → Linux x86_64 musl) ──────────────────── -# Build a static jcode binary for Linux x86_64 from a non-Linux host. -# No Docker needed — uses Chez xpatch + musl-gcc cross toolchain. -# -# Requires: -# - $(JERBOA_HOME)/.chez-cross-ta6le — cross-built Chez (make chez-cross in jerboa) -# - x86_64-linux-musl-gcc on PATH (brew install FiloSottile/musl-cross/musl-cross) -# - rustup target x86_64-unknown-linux-musl (rustup target add x86_64-unknown-linux-musl) -# -# Produces: jcode-linux-amd64 - -XC_LIBDIRS = ./lib:vendor/chez-sqlite/src:vendor/jerboa-websearch/src:$(JH)/lib:$(JERBOA_HOME)/lib - -linux-amd64: gen - @command -v x86_64-linux-musl-gcc >/dev/null 2>&1 || { \ - echo "ERROR: x86_64-linux-musl-gcc not found on PATH."; \ - echo "Install with: brew install FiloSottile/musl-cross/musl-cross"; \ - exit 1; } - @test -d $(JERBOA_HOME)/.chez-cross-ta6le || { \ - echo "ERROR: cross-built Chez not found at $(JERBOA_HOME)/.chez-cross-ta6le"; \ - echo "Build it with: cd $(JERBOA_HOME) && make chez-cross"; \ - exit 1; } - @command -v cargo >/dev/null 2>&1 || { \ - echo "ERROR: cargo not found on PATH. Install rustup from rustup.rs"; \ - exit 1; } - JERBOA_HOME=$(JERBOA_HOME) TARGET_ARCH=amd64 $(SCHEME) -q --libdirs "$(XC_LIBDIRS)" --script build-jcode-cross.ss - -linux-arm64: gen - @command -v aarch64-linux-musl-gcc >/dev/null 2>&1 || { \ - echo "ERROR: aarch64-linux-musl-gcc not found on PATH."; \ - echo "Install with: brew install FiloSottile/musl-cross/musl-cross"; \ - exit 1; } - @test -d $(JERBOA_HOME)/.chez-cross-tarm64le || { \ - echo "ERROR: cross-built Chez not found at $(JERBOA_HOME)/.chez-cross-tarm64le"; \ - echo "Build it with: cd $(JERBOA_HOME) && make chez-cross-tarm64le"; \ - exit 1; } - @command -v cargo >/dev/null 2>&1 || { \ - echo "ERROR: cargo not found on PATH. Install rustup from rustup.rs"; \ - exit 1; } - JERBOA_HOME=$(JERBOA_HOME) TARGET_ARCH=arm64 $(SCHEME) -q --libdirs "$(XC_LIBDIRS)" --script build-jcode-cross.ss - -# Friendly alias — same target, more explicit name. jcode-linux-amd64: linux-amd64 -test-linux-amd64: linux-amd64 - @echo "=== Smoke testing jcode-linux-amd64 under podman/qemu alpine ===" - @command -v podman >/dev/null 2>&1 || { \ - echo "ERROR: podman not found. Install with: brew install podman"; \ - exit 1; } - podman run --rm --platform linux/amd64 \ - -v "$(CURDIR):/work:ro" -w /work \ - alpine:3 ./jcode-linux-amd64 --version - -test-linux: test-linux-amd64 - -# ─── FreeBSD amd64 binary (cross-build from macOS) ────────────────────── -# Produces a dynamic x86_64 FreeBSD ELF (jcode-freebsd-amd64) from a macOS -# host. Depends on the target host's libc.so.7 / libm.so / libthr.so / -# libutil.so at runtime. -# -# Why dynamic and not static: FreeBSD libc uses symbol versioning -# (wait4@FBSD_1.0, etc.) that libc.a + libc_nonshared.a from base.txz -# cannot satisfy at link time. Dynamic linking is the standard FreeBSD -# distribution model anyway. -# -# Prereqs (set up once): -# - cd $(JERBOA_HOME) && make binary (builds .chez-cross-ta6fb/) -# - FreeBSD sysroot at $(JERBOA_HOME)/.freebsd-sysroot/amd64 -# - $(FREEBSD_AMD64_CC) -# - rustup target add x86_64-unknown-freebsd (one-time) - -freebsd-amd64: gen - @command -v $(firstword $(FREEBSD_AMD64_CC)) >/dev/null 2>&1 || { \ - echo "ERROR: $(FREEBSD_AMD64_CC) not found or not executable" >&2; \ - echo " See top of Makefile freebsd-amd64 target for setup notes." >&2; \ - exit 1; } - @test -d $(JERBOA_HOME)/.chez-cross-ta6fb || { \ - echo "ERROR: $(JERBOA_HOME)/.chez-cross-ta6fb not found" >&2; \ - echo " cd $(JERBOA_HOME) && make binary" >&2; \ - exit 1; } - @command -v cargo >/dev/null 2>&1 || { \ - echo "ERROR: cargo not found on PATH. Install rustup from rustup.rs"; \ - exit 1; } - JERBOA_HOME=$(JERBOA_HOME) CROSS_CC="$(FREEBSD_AMD64_CC)" $(SCHEME) -q --libdirs "$(XC_LIBDIRS)" --script build-jcode-freebsd-cross.ss +jcode-linux-arm64-native: gen $(NATIVE_DIR) + @case "$$(uname -s)-$$(uname -m)" in \ + Linux-aarch64|Linux-arm64) ;; \ + *) echo "ERROR: .jerbuild.linux-arm64 must run on Linux arm64/aarch64" >&2; exit 1 ;; \ + esac + @echo "=== Building native Linux arm64 jcode with jerbuild ===" + $(JERBUILD) build --config .jerbuild.linux-arm64 + @ls -lh jcode-linux-arm64 + @file jcode-linux-arm64 + +jcode-linux-arm64: linux-arm64 + +# ─── FreeBSD amd64 binary ─────────────────────────────────────────────────── +# Native FreeBSD build through installed jerbuild. Requires cc and cargo. + +freebsd-amd64: + @case "$$(uname -s)-$$(uname -m)" in \ + FreeBSD-x86_64|FreeBSD-amd64) ;; \ + *) echo "ERROR: freebsd-amd64 is a native jerbuild target; run it on FreeBSD amd64" >&2; exit 1 ;; \ + esac + @$(MAKE) jcode-freebsd-native + +jcode-freebsd-native: gen $(NATIVE_DIR) + @case "$$(uname -s)-$$(uname -m)" in \ + FreeBSD-x86_64|FreeBSD-amd64) ;; \ + *) echo "ERROR: .jerbuild.freebsd-amd64 must run on FreeBSD amd64" >&2; exit 1 ;; \ + esac + @echo "=== Building native FreeBSD amd64 jcode with jerbuild ===" + $(JERBUILD) build --config .jerbuild.freebsd-amd64 + @ls -lh jcode-freebsd-amd64 + @file jcode-freebsd-amd64 -# Friendly aliases. jcode-freebsd-amd64: freebsd-amd64 -# `make freebsd` defaults to the cross-from-macOS path (matches `make linux`). -# For a native-on-FreeBSD build (legacy build-binary.ss code path), run -# `make build` from a FreeBSD host instead. freebsd: freebsd-amd64 @@ -416,7 +337,7 @@ clean: find lib/jcode -name "*.sls" -delete 2>/dev/null; true find . -name "*.so" -delete find . -name "*.wpo" -delete - rm -f jcode jcode-musl jcode-musl.sha256 + rm -f jcode jcode-linux-amd64 jcode-linux-arm64 jcode-freebsd-amd64 rm -f lib/libjerboa_native.dylib lib/libjerboa_native.so jcode_tui_shim.dylib jcode_tui_shim.so # ── Android APK (thin client, no embedded binary) ─────────────────────────── --- a/README.md +++ b/README.md @@ -3,7 +3,7 @@ **A portable AI coding agent written in [Jerboa](https://git.sr.ht/~lisp/jerboa) Scheme.** `jcode` is a terminal coding agent — think opencode / aider / Claude Code — that -compiles to a single static binary with no runtime dependencies. It talks to 13 +compiles to a standalone binary without a Node or Python runtime. It talks to 13 LLM providers (cloud and local), drives your editor through a real tool loop, and ships a reliability layer that makes even small self-hosted models call tools dependably. @@ -24,7 +24,7 @@ tools dependably. ## Why it exists -- **Portable.** One static binary. Runs on macOS, Linux (glibc + musl), FreeBSD, +- **Portable.** One standalone binary. Runs on macOS, Linux, FreeBSD, and Android (via Termux). No Node, no Python, no ecosystem. - **Provider-agnostic.** Anthropic, OpenAI, Google, OpenRouter, DeepSeek, xAI, Groq, Mistral, Together, Cerebras, Perplexity — plus local **Ollama** and @@ -38,9 +38,9 @@ tools dependably. ## Quickstart -You need a built [jerboa](https://git.sr.ht/~lisp/jerboa) checkout (`JERBOA_HOME`) -and a Rust toolchain. See **[docs/getting-started.md](docs/getting-started.md)** -for the full setup. +You need the installed Jerboa toolchain (`jerbuild` on `PATH`), a C compiler, +and Rust/Cargo. See **[docs/getting-started.md](docs/getting-started.md)** for +the full setup. ```bash git clone https://git.sr.ht/~lisp/jerboa-code && cd jerboa-code @@ -72,7 +72,7 @@ See **[docs/](docs/)** for the full index. ## Build targets `make build` · `test` · `run` · `run-tui` · `binary` · `install` · -`linux` · `linux-arm64` · `linux-docker` · `freebsd` · `android`. +`linux` · `linux-amd64` · `linux-arm64` · `freebsd` · `android`. Run `make help` for the complete list. ## Layout deleted file mode 100644 --- a/build-binary.ss +++ /dev/null @@ -1,640 +0,0 @@ -#!chezscheme -;; Build a native jcode binary. -;; -;; Usage: cd jerboa-code && make binary -;; -;; Produces: ./jcode (single binary with embedded boot files + program) -;; -;; All boot files are embedded as C byte arrays via Sregister_boot_file_bytes. -;; SQLite shim is statically linked; chez-sqlite uses dlopen(NULL) to resolve. - -(import (chezscheme)) - -;; --- Helper: generate C header from binary file --- -(define (file->c-header input-path output-path array-name size-name) - (let* ((port (open-file-input-port input-path)) - (data (get-bytevector-all port)) - (size (bytevector-length data))) - (close-port port) - (call-with-output-file output-path - (lambda (out) - (fprintf out "/* Auto-generated — do not edit */~n") - (fprintf out "static const unsigned char ~a[] = {~n" array-name) - (let loop ((i 0)) - (when (< i size) - (when (= 0 (modulo i 16)) (fprintf out " ")) - (fprintf out "0x~2,'0x" (bytevector-u8-ref data i)) - (when (< (+ i 1) size) (fprintf out ",")) - (when (= 15 (modulo i 16)) (fprintf out "~n")) - (loop (+ i 1)))) - (fprintf out "~n};~n") - (fprintf out "static const unsigned int ~a = ~a;~n" size-name size)) - 'replace) - (printf " ~a: ~a bytes~n" output-path size))) - -;; --- Detect OS --- -(define freebsd? - (let ((mt (symbol->string (machine-type)))) - (or (string=? mt "ta6fb") (string=? mt "a6fb") - (string=? mt "tarm64fb") (string=? mt "arm64fb")))) - -(define (string-has-suffix? s suffix) - (let ((slen (string-length s)) - (suflen (string-length suffix))) - (and (>= slen suflen) - (string=? suffix (substring s (- slen suflen) slen))))) - -(define macos? - (string-has-suffix? (symbol->string (machine-type)) "osx")) - -(define termux? - (and (getenv "PREFIX") - (let ((prefix (getenv "PREFIX"))) - (and (string? prefix) (> (string-length prefix) 0) - (file-exists? (format "~a/bin/termux-info" prefix)))))) - -;; --- Locate Chez install directory --- -(define (find-csv-dir lib-dir mt) - (let ((csv-dir - (let lp ((dirs (guard (e (#t '())) (directory-list lib-dir)))) - (cond - ((null? dirs) #f) - ((and (> (string-length (car dirs)) 3) - (string=? "csv" (substring (car dirs) 0 3))) - (format "~a/~a/~a" lib-dir (car dirs) mt)) - (else (lp (cdr dirs))))))) - (and csv-dir - (file-exists? (format "~a/main.o" csv-dir)) - csv-dir))) - -(define chez-dir - (or (getenv "CHEZ_DIR") - (let ((mt (symbol->string (machine-type))) - (home (getenv "HOME")) - (jerboa-home (or (getenv "JERBOA_HOME") - (format "~a/mine/jerboa" (getenv "HOME"))))) - ;; Prefer the self-built Chez under $JERBOA_HOME/.chez (canonical - ;; since jerboa commit 3fe0459 — `make binary` there builds it). - (or (find-csv-dir (format "~a/.chez/lib" jerboa-home) mt) - (find-csv-dir (format "~a/.local/lib" home) mt) - (find-csv-dir "/usr/local/lib" mt) - (find-csv-dir "/usr/lib" mt) - (find-csv-dir "/opt/homebrew/lib" mt) - (let ((prefix (getenv "PREFIX"))) - (and prefix (find-csv-dir (format "~a/lib" prefix) mt))))))) - -(unless chez-dir - (display "Error: Cannot find Chez install dir. Set CHEZ_DIR.\n") - (exit 1)) - -(define home (getenv "HOME")) -(define jerboa-dir - (or (getenv "JERBOA_HOME") - (format "~a/mine/jerboa" home))) - -(printf "Chez dir: ~a~n" chez-dir) -(printf "Jerboa dir: ~a~n" jerboa-dir) - -;; Add library search paths -(library-directories - (append - (list (cons (format "~a/lib" jerboa-dir) - (format "~a/lib" jerboa-dir))) - (list (cons "lib" "lib")) - (list (cons "vendor/chez-sqlite/src" "vendor/chez-sqlite/src")) - (list (cons "vendor/jerboa-websearch/src" "vendor/jerboa-websearch/src")) - (list (cons "." ".")) - (library-directories))) - -(define jcode-modules - '("lib/jcode/core/models" - "lib/jcode/core/config" - "lib/jcode/core/log" - "lib/jcode/core/errors" - "lib/jcode/core/hardware" - "lib/jcode/core/steps" - "lib/jcode/core/workflow" - "lib/jcode/core/session" - "lib/jcode/core/message" - "lib/jcode/core/secrets" - "lib/jcode/core/secrets-import" - "lib/jcode/core/escalation" - "lib/jcode/core/permissions" - "lib/jcode/core/mentions" - "lib/jcode/core/agents-md" - "lib/jcode/core/hooks" - "lib/jcode/core/compaction" - "lib/jcode/core/compaction-strategy" - "lib/jcode/core/sandbox" - "lib/jcode/core/repomap" - "lib/jcode/core/checkpoints" - "lib/jcode/core/expert" - "lib/jcode/core/agent" - "lib/jcode/core/plugin" - "lib/jcode/core/debug-repl" - "lib/jcode/core/skill" - "lib/jcode/core/builtin-skills" - "lib/jcode/guardrails/nudge" - "lib/jcode/guardrails/error-tracker" - "lib/jcode/guardrails/message-type" - "lib/jcode/guardrails/rescue" - "lib/jcode/guardrails/validator" - "lib/jcode/guardrails/respond" - "lib/jcode/guardrails/guardrails" - "lib/jcode/guardrails/step-enforcer" - "lib/jcode/core/workflow-runner" - "lib/jcode/core/verified" - "lib/jcode/core/best-of-k" - "lib/jcode/provider/sampling" - "lib/jcode/provider/provider" - "lib/jcode/proxy/convert" - "lib/jcode/proxy/handler" - "lib/jcode/core/slot-worker" - "lib/jcode/proxy/server" - "lib/jcode/core/verified-run" - "lib/jcode/eval/scenario" - "lib/jcode/eval/ablation" - "lib/jcode/eval/runner" - "lib/jcode/tool/registry" - "lib/jcode/tool/file" - "lib/jcode/tool/apply-patch" - "lib/jcode/tool/bash" - "lib/jcode/tool/task" - "lib/jcode/tool/repomap-tool" - "lib/jcode/tool/web" - "lib/jcode/tool/batch" - "lib/jcode/tool/git" - "lib/jcode/tool/external-llm" - "lib/jcode/tool/lsp" - "lib/jcode/mcp/client" - "lib/jcode/ui/tui-ffi" - "lib/jcode/ui/tui-theme" - "lib/jcode/ui/tui-keys" - "lib/jcode/ui/tui-markdown" - "lib/jcode/ui/tui-diff" - "lib/jcode/ui/tui-message" - "lib/jcode/ui/tui-status" - "lib/jcode/ui/tui-input" - "lib/jcode/ui/tui-memstats" - "lib/jcode/ui/tui-sidebar" - "lib/jcode/ui/tui-dialog" - "lib/jcode/ui/tui-toast" - "lib/jcode/ui/tui-syntax" - "lib/jcode/ui/tui" - "lib/jcode/ui/relay" - "lib/jcode/ui/connect" - "lib/jcode/ui/cli")) - -;; --- Step 0: Clean stale .so files so WPO can recompile everything --- -;; Vendor .so/.wpo pairs must be deleted together: if only the .wpo is -;; stale relative to its .so, compile-imported-libraries sees the .so as -;; up-to-date and skips regeneration, leaving compile-whole-program to -;; fail with "does not define expected compilation instance of library". -(printf "~n[0/6] Cleaning stale .so/.wpo files...~n") -(for-each (lambda (m) - (let ((so (format "~a.so" m)) - (wpo (format "~a.wpo" m))) - (when (file-exists? so) (delete-file so)) - (when (file-exists? wpo) (delete-file wpo)))) - jcode-modules) -(system (format "find ~a/lib -name '*.wpo' -delete 2>/dev/null" jerboa-dir)) -(system "find vendor/jerboa-websearch/src -name '*.so' -delete 2>/dev/null") -(system "find vendor/jerboa-websearch/src -name '*.wpo' -delete 2>/dev/null") - -;; --- Step 0.5: Patch chez-sqlite for static linking --- -;; In the static binary, the shim is compiled into the binary itself. -;; We patch chez-sqlite to use (load-shared-object "") which is dlopen(NULL), -;; resolving symbols already linked into the process (like jerboa-shell does). -(printf "[0.5/6] Patching chez-sqlite for static linking...~n") -(define chez-sqlite-sls "vendor/chez-sqlite/src/chez-sqlite.sls") -(define chez-sqlite-backup "vendor/chez-sqlite/src/chez-sqlite.sls.bak") -(system (format "cp ~a ~a" chez-sqlite-sls chez-sqlite-backup)) -;; For static builds: sqlite3 and the shim are linked into the binary, -;; so load-shared-object is unnecessary. Replace _l1/_l2 with no-ops.