Add Docker base image for static musl binary builds

ober

019fe6c5706822d241560b7ef0af72ba7dd752fa

diff --git a/Dockerfile b/Dockerfile
new file mode 100644
index 0000000..890ee7d
--- /dev/null
+++ b/Dockerfile
@@ -0,0 +1,90 @@
+# Dockerfile — jerboa21/jerboa base image for static binary builds
+#
+# Provides:
+#   - Stock Chez Scheme (glibc) at /usr/local — for compilation steps
+#   - Musl Chez Scheme (static) at /build/chez-musl — for linking
+#   - Jerboa library source at /build/mine/jerboa/lib
+#   - musl-gcc, build-essential, and all linking deps pre-installed
+#
+# Downstream projects (gitsafe, etc.) use this as their FROM image
+# to skip the expensive Chez double-build. They just COPY their source
+# and run their musl build script.
+#
+# Build & push:
+#   make docker-build
+#   make docker-push
+#
+# Or manually:
+#   docker build --platform linux/amd64 -t jerboa21/jerboa .
+#   docker push jerboa21/jerboa
+
+FROM ubuntu:24.04
+
+ARG DEBIAN_FRONTEND=noninteractive
+
+# ── System dependencies for static builds ────────────────────────────────────
+RUN apt-get update && apt-get install -y --no-install-recommends \
+    build-essential \
+    musl-tools \
+    musl-dev \
+    git \
+    ca-certificates \
+    curl \
+    libncurses-dev \
+    uuid-dev \
+    liblz4-dev \
+    zlib1g-dev \
+    file \
+    && rm -rf /var/lib/apt/lists/*
+
+# Set HOME=/build so no real usernames or home directories leak into binaries
+ENV HOME=/build
+WORKDIR /build
+
+# ── Build Chez Scheme (stock glibc, for compilation steps) ───────────────────
+# Installed to /usr/local so `scheme` is on PATH
+RUN git clone --depth 1 https://github.com/ober/ChezScheme.git && \
+    cd ChezScheme && \
+    git submodule update --init --depth 1 && \
+    ./configure --threads --disable-x11 --installprefix=/usr/local && \
+    make -j$(nproc) && \
+    make install && \
+    cd /build && rm -rf ChezScheme
+
+# ── Build Chez Scheme (musl, for static linking) ────────────────────────────
+# Two-pass build:
+#   Pass 1: Full build with stock gcc to generate boot files
+#   Pass 2: Rebuild kernel only with musl-gcc --static, reusing boot files
+# Installed to /build/chez-musl
+RUN git clone https://github.com/ober/ChezScheme.git chez-musl-src && \
+    cd chez-musl-src && \
+    git submodule update --init && \
+    ./configure --threads --disable-x11 --installprefix=/build/chez-musl && \
+    make -j$(nproc) && \
+    cp ta6le/boot/ta6le/petite.boot /tmp/petite.boot && \
+    cp ta6le/boot/ta6le/scheme.boot /tmp/scheme.boot && \
+    make clean && \
+    ./configure --threads --disable-x11 --static CC=musl-gcc --installprefix=/build/chez-musl && \
+    mkdir -p ta6le/boot/ta6le && \
+    cp /tmp/petite.boot ta6le/boot/ta6le/ && \
+    cp /tmp/scheme.boot ta6le/boot/ta6le/ && \
+    make -j$(nproc) kernel && \
+    make install && \
+    cd /build && rm -rf chez-musl-src /tmp/petite.boot /tmp/scheme.boot
+
+# ── Copy Jerboa library source ───────────────────────────────────────────────
+WORKDIR /build/mine
+COPY lib /build/mine/jerboa/lib
+
+# ── Set default environment for downstream builds ───────────────────────────
+ENV JERBOA_MUSL_CHEZ_PREFIX=/build/chez-musl
+ENV JERBOA_HOME=/build/mine/jerboa
+
+# ── Smoke test ───────────────────────────────────────────────────────────────
+RUN scheme --version && \
+    musl-gcc --version | head -1 && \
+    test -d /build/chez-musl && \
+    echo "jerboa21/jerboa base image ready"
+
+WORKDIR /build
+CMD ["/bin/bash"]
diff --git a/Makefile b/Makefile
index 016c143..dbf9ef6 100644
--- a/Makefile
+++ b/Makefile
@@ -7,7 +7,7 @@ CHEZ_EXT_LIBDIRS = $(CHEZ_EXT_DIR)/chez-https/src:$(CHEZ_EXT_DIR)/chez-ssl/src:$
 # Shared object paths for legacy FFI-based chez-* libraries
 CHEZ_EXT_LDPATH = $(CHEZ_EXT_DIR)/chez-ssl:$(CHEZ_EXT_DIR)/chez-zlib:$(CHEZ_EXT_DIR)/chez-pcre2:$(CHEZ_EXT_DIR)/chez-leveldb:$(CHEZ_EXT_DIR)/chez-epoll:$(CHEZ_EXT_DIR)/chez-inotify:$(CHEZ_EXT_DIR)/chez-crypto:$(CHEZ_EXT_DIR)/chez-sqlite:$(CHEZ_EXT_DIR)/chez-postgresql
 
-.PHONY: build test test-reader test-core test-runtime test-stdlib test-ffi test-modules test-expanded test-features test-wrappers test-phase4a test-phase4b test-phase4c test-phase4d test-phase4e test-phase4f test-phase5 test-phase5e test-phase6 test-phase7 test-phase8 test-functional test-repl test-security test-native test-gaps native clean-native audit-native clean fuzz fuzz-smoke fuzz-deep fuzz-reader-fuzz fuzz-json-fuzz fuzz-http2-fuzz fuzz-websocket-fuzz fuzz-dns-fuzz fuzz-pregexp-fuzz fuzz-csv-fuzz fuzz-base64-fuzz fuzz-hex-fuzz fuzz-uri-fuzz fuzz-format-fuzz fuzz-router-fuzz fuzz-sandbox-fuzz test-rawstring test-regex test-rx test-peg test-regex-all
+.PHONY: build test test-reader test-core test-runtime test-stdlib test-ffi test-modules test-expanded test-features test-wrappers test-phase4a test-phase4b test-phase4c test-phase4d test-phase4e test-phase4f test-phase5 test-phase5e test-phase6 test-phase7 test-phase8 test-functional test-repl test-security test-native test-gaps native clean-native audit-native clean fuzz fuzz-smoke fuzz-deep fuzz-reader-fuzz fuzz-json-fuzz fuzz-http2-fuzz fuzz-websocket-fuzz fuzz-dns-fuzz fuzz-pregexp-fuzz fuzz-csv-fuzz fuzz-base64-fuzz fuzz-hex-fuzz fuzz-uri-fuzz fuzz-format-fuzz fuzz-router-fuzz fuzz-sandbox-fuzz test-rawstring test-regex test-rx test-peg test-regex-all docker-build docker-push
 
 build:
 	$(SCHEME) --libdirs $(LIBDIRS) --script support/build.ss
@@ -376,3 +376,19 @@ fuzz-sandbox-fuzz:
 clean:
 	find lib -name "*.so" -delete 2>/dev/null || true
 	find lib -name "*.wpo" -delete 2>/dev/null || true
+
+# ── Docker base image (jerboa21/jerboa) ──────────────────────────────────────
+# Base image for building static musl binaries of Jerboa projects.
+# Includes: stock Chez, musl Chez, jerboa lib, musl-gcc, build deps.
+DOCKER_IMAGE = jerboa21/jerboa
+
+docker-build:
+	@echo "=== Building $(DOCKER_IMAGE) base image ==="
+	docker build --platform linux/amd64 -t $(DOCKER_IMAGE) .
+	@echo ""
+	@docker images $(DOCKER_IMAGE) --format "Image: {{.Repository}}:{{.Tag}}  Size: {{.Size}}"
+
+docker-push: docker-build
+	@echo "=== Pushing $(DOCKER_IMAGE) to Docker Hub ==="
+	docker push $(DOCKER_IMAGE)
+	@echo "Pushed $(DOCKER_IMAGE)"