Use Jerboa artifacts without gherkin
ober
336a1d230f8ae0797cc771e7aa04b427f014a3da
--- a/.gitignore +++ b/.gitignore @@ -11,10 +11,14 @@ lib/**/*.wpo # Build symlinks / local artifacts libjsh-ffi.so +/.jerboa/ # Build outputs (binaries, objects, boot files, generated headers) jemacs jemacs-qt +main.so +main.wpo +jemacs-all.so *.o *.boot *_boot.h --- a/Dockerfile +++ b/Dockerfile @@ -1,6 +1,6 @@ # Intermediate Podman image for jemacs-qt static builds. # Bakes static Qt6 + QScintilla from source, plus all Chez Scheme -# dependencies (jerboa, gherkin, jsh, chez-pcre2, chez-scintilla, +# dependencies (jerboa, jsh, chez-pcre2, chez-scintilla, # chez-qt) so that subsequent jemacs-qt builds only compile jemacs # itself (~5-10 min instead of ~30 min). # @@ -259,7 +259,6 @@ ENV SCHEME=/opt/chez/bin/scheme # Copy dependency sources from build contexts COPY --from=jerboa-src . /deps/jerboa -COPY --from=gherkin-src . /deps/gherkin COPY --from=jsh-src . /deps/jsh COPY --from=pcre2-src . /deps/chez-pcre2 COPY --from=sci-src . /deps/chez-scintilla @@ -274,7 +273,7 @@ COPY vendor/qt_chez_shim.c vendor/qt_shim.h /deps/chez-qt/ # need to compile jemacs-specific modules. COPY support/static-precompile-deps.ss /tmp/static-precompile-deps.ss RUN /opt/chez/bin/scheme \ - --libdirs /deps/jerboa/lib:/deps/gherkin:/deps/jsh/src:/deps/chez-pcre2:/deps/chez-scintilla/src:/deps/chez-qt \ + --libdirs /deps/jerboa/lib:/deps/jsh/src:/deps/jsh/vendor/jerboa-coreutils/lib:/deps/jsh/vendor/jerboa-awk/lib:/deps/jsh/vendor/jerboa-sed/lib:/deps/chez-pcre2:/deps/chez-scintilla/src:/deps/chez-qt \ --compile-imported-libraries \ --script /tmp/static-precompile-deps.ss --- a/Makefile +++ b/Makefile @@ -1,5 +1,19 @@ VENDOR ?= $(CURDIR)/vendor +JERBOA_VERSION ?= v0.2.0 +JERBOA_TOOL_DIR ?= $(CURDIR)/.jerboa/bin +JERBUILD_BIN ?= $(shell if [ -x ./jerbuild ] && [ -x ./jerboa ]; then \ + printf '%s\n' "$(CURDIR)/jerbuild"; \ +elif [ -x "$(JERBOA_TOOL_DIR)/jerbuild" ] && [ -x "$(JERBOA_TOOL_DIR)/jerboa" ]; then \ + printf '%s\n' "$(JERBOA_TOOL_DIR)/jerbuild"; \ +elif [ -x ../jerboa/dist/jerbuild ] && [ -x ../jerboa/dist/jerboa ]; then \ + printf '%s\n' "$(abspath ../jerboa/dist/jerbuild)"; \ +elif command -v jerbuild >/dev/null 2>&1 && command -v jerboa >/dev/null 2>&1; then \ + command -v jerbuild; \ +else \ + printf '%s\n' "$(JERBOA_TOOL_DIR)/jerbuild"; \ +fi) + JERBOA_REPO ?= https://git.sr.ht/~lisp/jerboa JERBOA_SHELL_REPO ?= https://git.sr.ht/~lisp/jerboa-shell JERBOA_PCRE2_REPO ?= https://git.sr.ht/~lisp/jerboa-pcre2 @@ -43,7 +57,6 @@ JERBOA_SSH ?= $(JSH_VENDOR)/jerboa-ssh/src JERBOA_SQLITE ?= $(JSH_VENDOR)/jerboa-sqlite/src JERBOA_CRYPTO ?= $(JSH_VENDOR)/jerboa-crypto/src JERBOA_FUSE ?= $(JSH_VENDOR)/jerboa-fuse/lib -GHERKIN ?= $(VENDOR)/gherkin-runtime JAWS_ROOT ?= $(VENDOR)/jerboa-aws JAWS ?= $(JAWS_ROOT)/lib JERBOA_SSL_ROOT ?= $(VENDOR)/jerboa-ssl @@ -52,13 +65,15 @@ JERBOA_HTTPS_ROOT ?= $(VENDOR)/jerboa-https CHTTPS ?= $(JERBOA_HTTPS_ROOT)/src CQT ?= $(VENDOR)/jerboa-qt JERBOA_PCRE2_ROOT ?= $(VENDOR)/jerboa-pcre2 +JERBOA_PCRE2_LIBDIR ?= $(JERBOA_PCRE2_ROOT)/lib JERBOA_SCINTILLA_ROOT ?= $(VENDOR)/jerboa-scintilla +JERBOA_SCINTILLA_LIBDIR ?= $(JERBOA_SCINTILLA_ROOT)/lib AWS_LIBDIRS := ifeq ($(JEMACS_ENABLE_AWS),1) AWS_LIBDIRS := :$(JAWS):$(CSSL):$(CHTTPS) endif -LIBDIRS = --libdirs lib:$(JERBOA)/lib:$(JSH):$(COREUTILS):$(JSH_AWK):$(JSH_SED):$(JERBOA_SSH):$(JERBOA_SQLITE):$(JERBOA_CRYPTO):$(JERBOA_FUSE):$(GHERKIN):$(JERBOA_PCRE2_ROOT):$(JERBOA_SCINTILLA_ROOT)/src:$(CQT)$(AWS_LIBDIRS) -JERBUILD = $(SCHEME) --libdirs $(JERBOA)/lib --script $(JERBOA)/jerbuild.ss +LIBDIRS = --libdirs lib:$(JERBOA)/lib:$(JSH):$(COREUTILS):$(JSH_AWK):$(JSH_SED):$(JERBOA_SSH):$(JERBOA_SQLITE):$(JERBOA_CRYPTO):$(JERBOA_FUSE):$(JERBOA_PCRE2_LIBDIR):$(JERBOA_SCINTILLA_LIBDIR):$(CQT)$(AWS_LIBDIRS) +JERBUILD ?= $(JERBUILD_BIN) transpile # --- Platform detection ------------------------------------------------------- UNAME_S := $(shell uname -s) @@ -89,17 +104,22 @@ else endif NATIVE_LIB := $(JERBOA)/lib/libjerboa_native.$(SHLIB_EXT) SSL_SHIM := $(JERBOA_SSL_ROOT)/jerboa_ssl_shim.$(SHLIB_EXT) +SCINTILLA_SHIM := ./jerboa_scintilla_shim.$(SHLIB_EXT) PRELOAD_ENV := $(PRELOAD_VAR)=./libqt_shim.$(SHLIB_EXT):./jerboa_qt_shim.$(SHLIB_EXT):$(NATIVE_LIB):./libjsh-ffi.$(SHLIB_EXT):./libjsh_coreutils_stub.$(SHLIB_EXT):$(SSL_SHIM) +CORE_PRELOAD_ENV := $(PRELOAD_VAR)=$(NATIVE_LIB):$(SCINTILLA_SHIM):./libjsh-ffi.$(SHLIB_EXT):./libjsh_coreutils_stub.$(SHLIB_EXT):$(SSL_SHIM) # ----------------------------------------------------------------------------- -export JERBOA_SCINTILLA_LIB := $(JERBOA_SCINTILLA_ROOT) +export JERBOA_SCINTILLA_LIB := $(CURDIR) export JERBOA_PCRE2_LIB := $(JERBOA_PCRE2_ROOT) export JSH_FFI_LIB := $(JSH_ROOT) export JERBOA_SSL_DIR := $(JERBOA_SSL_ROOT) export JERBOA_QT_LIB := . export JERBOA_QT_SHIM_DIR := . ifeq ($(UNAME_S),Darwin) - export CHEZ_DIR := $(shell ls -d /opt/homebrew/lib/csv*/tarm64osx 2>/dev/null | head -1) + HOMEBREW_CHEZ_DIR := $(shell ls -d /opt/homebrew/lib/csv*/tarm64osx 2>/dev/null | head -1) + ifneq ($(HOMEBREW_CHEZ_DIR),) + export CHEZ_DIR ?= $(HOMEBREW_CHEZ_DIR) + endif endif SCHEME_PREFIX = $(abspath $(dir $(SCHEME))/..) SCHEME_MT = $(shell if [ -x "$(SCHEME)" ]; then printf '(display (machine-type))\n' | "$(SCHEME)" -q 2>/dev/null; fi) @@ -107,7 +127,7 @@ SCHEME_CHEZ_DIR = $(shell if [ -n "$(SCHEME_MT)" ]; then ls -d "$(SCHEME_PREFIX) CHEZ_DIR ?= $(SCHEME_CHEZ_DIR) export CHEZ_DIR -.PHONY: all vendor-deps deps build rebuild run test-tier0 test-tier2 test-tier3 test-tier4 test-tier5 test-org test-extra test clean clean-generated \ +.PHONY: all vendor-deps deps ensure-jerboa-tools scintilla-vendor-deps scintilla-vendor-clean build rebuild run test-tier0 test-tier2 test-tier3 test-tier4 test-tier5 test-org test-extra test clean clean-generated \ test-org-duration test-org-element test-org-fold test-org-footnote \ test-org-lint test-org-num test-org-property test-org-src test-org-tempo \ test-vtscreen test-debug-repl test-qt test-qt-e2e build-qt binary-qt \ @@ -127,6 +147,8 @@ export CHEZ_DIR all: @echo "Available targets:" @echo " vendor-deps Clone required chez-* and jerboa-* deps into vendor/" + @echo " ensure-jerboa-tools Ensure jerboa/jerbuild are available" + @echo " scintilla-vendor-deps Fetch/build Scintilla, Lexilla, and termbox archives" @echo " build Translate src/*.ss → lib/*.sls (incremental)" @echo " rebuild Force full retranslation" @echo " run Build and run TUI editor" @@ -183,14 +205,33 @@ vendor-deps: deps: vendor-deps $(MAKE) -C $(JSH_ROOT) vendor-deps $(MAKE) -C $(JERBOA) build - $(MAKE) -C $(JERBOA_PCRE2_ROOT) SCHEME=$(SCHEME) + $(MAKE) -C $(JERBOA_PCRE2_ROOT) SCHEME=$(SCHEME) JERBOA_HOME=$(JERBOA) JERBUILD=$(JERBUILD_BIN) + $(MAKE) -C $(JERBOA_SCINTILLA_ROOT) JERBOA_HOME=$(JERBOA) JERBUILD=$(JERBUILD_BIN) transpile + +ensure-jerboa-tools: + @if [ -x ./jerbuild ] && [ -x ./jerboa ]; then \ + echo "=== Using project-local ./jerbuild ==="; \ + elif [ -x "$(JERBOA_TOOL_DIR)/jerbuild" ] && [ -x "$(JERBOA_TOOL_DIR)/jerboa" ]; then \ + echo "=== Using downloaded Jerboa toolchain: $(JERBOA_TOOL_DIR) ==="; \ + elif [ -x ../jerboa/dist/jerbuild ] && [ -x ../jerboa/dist/jerboa ]; then \ + echo "=== Using sibling Jerboa build: ../jerboa/dist/jerbuild ==="; \ + elif command -v jerbuild >/dev/null 2>&1 && command -v jerboa >/dev/null 2>&1; then \ + echo "=== Using Jerboa toolchain from PATH: $$(command -v jerbuild) ==="; \ + else \ + echo "=== Fetching Jerboa $(JERBOA_VERSION) release tools into $(JERBOA_TOOL_DIR) ==="; \ + sh support/ensure-jerboa.sh "$(JERBOA_VERSION)" "$(JERBOA_TOOL_DIR)"; \ + fi + @"$(JERBUILD_BIN)" --jerboa-home >/dev/null || { \ + echo "ERROR: Jerboa toolchain is unavailable; set JERBUILD_BIN=/path/to/jerbuild or JERBOA_VERSION=<tag>"; \ + exit 1; \ + } # Generate lib/jerboa-emacs/*.sls from src/jerboa-emacs/*.ss (incremental) -build: deps +build: ensure-jerboa-tools deps $(JERBUILD) src/ lib/ # Force regenerate all -rebuild: deps +rebuild: ensure-jerboa-tools deps $(JERBUILD) src/ lib/ --force check-generated: @@ -293,14 +334,14 @@ jerboa_qt_shim.$(SHLIB_EXT): vendor/jerboa_qt_shim.c vendor/qt_shim.h libjsh-ffi.$(SHLIB_EXT): $(JSH_ROOT)/ffi-shim.c gcc $(SHLIB_FLAGS) -O2 -o libjsh-ffi.$(SHLIB_EXT) $(JSH_ROOT)/ffi-shim.c -Wall -libjsh_coreutils_stub.$(SHLIB_EXT): vendor/libjsh_coreutils_stub.a - gcc $(SHLIB_FLAGS) -o libjsh_coreutils_stub.$(SHLIB_EXT) -Wl,--whole-archive vendor/libjsh_coreutils_stub.a -Wl,--no-whole-archive +libjsh_coreutils_stub.$(SHLIB_EXT): support/jsh_coreutils_stubs.c + gcc $(SHLIB_FLAGS) -O2 -o libjsh_coreutils_stub.$(SHLIB_EXT) support/jsh_coreutils_stubs.c -Wall $(NATIVE_LIB): $(MAKE) -C $(JERBOA) native $(SSL_SHIM): $(JERBOA_SSL_ROOT)/jerboa_ssl_shim.c - $(MAKE) -C $(JERBOA_SSL_ROOT) + $(MAKE) -C $(JERBOA_SSL_ROOT) JERBOA_HOME=$(JERBOA) SCHEME=$(SCHEME) JERBUILD=$(JERBUILD_BIN) # macOS native binary — compile all modules + link jemacs-qt binary macos: build libqt_shim.$(SHLIB_EXT) jerboa_qt_shim.$(SHLIB_EXT) repl_shim.$(SHLIB_EXT) vterm_shim.$(SHLIB_EXT) @@ -486,8 +527,8 @@ test-qt-e2e: test-emacs: $(SCHEME) $(LIBDIRS) --program tests/test-emacs.ss -test-functional: build libjsh-ffi.$(SHLIB_EXT) libjsh_coreutils_stub.$(SHLIB_EXT) $(NATIVE_LIB) $(SSL_SHIM) - $(PRELOAD_ENV) $(SCHEME) $(LIBDIRS) --program tests/test-functional.ss +test-functional: build jerboa_scintilla_shim.$(SHLIB_EXT) libjsh-ffi.$(SHLIB_EXT) libjsh_coreutils_stub.$(SHLIB_EXT) $(NATIVE_LIB) $(SSL_SHIM) + $(CORE_PRELOAD_ENV) $(SCHEME) $(LIBDIRS) --program tests/test-functional.ss test-pty: $(SCHEME) $(LIBDIRS) --script tests/test-pty.ss @@ -502,10 +543,61 @@ binary-qt: build # binaries, must live under the vendored jerboa-scintilla checkout. SCI_DIR ?= $(JERBOA_SCINTILLA_ROOT) SCINTILLA_VENDOR ?= $(SCI_DIR)/vendor +SCINTILLA_VER ?= 558 +LEXILLA_VER ?= 546 +SCINTILLA_URL ?= https://scintilla.org/scintilla$(SCINTILLA_VER).tgz +LEXILLA_URL ?= https://scintilla.org/lexilla$(LEXILLA_VER).tgz +SCINTILLA_TB_URL ?= https://github.com/masahino/scintilla-termbox +TERMBOX_URL ?= https://github.com/masahino/termbox_next +SCI_VENDOR_SCINTILLA_DIR := $(SCINTILLA_VENDOR)/scintilla +SCI_VENDOR_LEXILLA_DIR := $(SCINTILLA_VENDOR)/lexilla +SCI_VENDOR_TB_DIR := $(SCI_VENDOR_SCINTILLA_DIR)/termbox +SCI_VENDOR_TERMBOX_DIR := $(SCI_VENDOR_TB_DIR)/termbox_next +SCI_VENDOR_SCINTILLA_A := $(SCI_VENDOR_SCINTILLA_DIR)/bin/scintilla.a +SCI_VENDOR_LEXILLA_A := $(SCI_VENDOR_LEXILLA_DIR)/bin/liblexilla.a +SCI_VENDOR_TERMBOX_A := $(SCI_VENDOR_TERMBOX_DIR)/bin/termbox.a +SCI_VENDOR_SCINTILLA_H := $(SCI_VENDOR_SCINTILLA_DIR)/include/Scintilla.h +SCI_VENDOR_LEXILLA_H := $(SCI_VENDOR_LEXILLA_DIR)/include/Lexilla.h +SCI_VENDOR_TB_H := $(SCI_VENDOR_TB_DIR)/ScintillaTermbox.h +SCI_VENDOR_TERMBOX_H := $(SCI_VENDOR_TERMBOX_DIR)/src/termbox.h + +ifeq ($(UNAME_S),Darwin) + SCINTILLA_ARCHIVES = -Wl,-force_load,$(SCI_VENDOR_SCINTILLA_A) -Wl,-force_load,$(SCI_VENDOR_LEXILLA_A) -Wl,-force_load,$(SCI_VENDOR_TERMBOX_A) + SCINTILLA_STDLIBS = -lc++ -lpthread +else + SCINTILLA_ARCHIVES = -Wl,--whole-archive $(SCI_VENDOR_SCINTILLA_A) $(SCI_VENDOR_LEXILLA_A) $(SCI_VENDOR_TERMBOX_A) -Wl,--no-whole-archive + SCINTILLA_STDLIBS = -lstdc++ -lpthread +endif + +scintilla-vendor-deps: $(SCI_VENDOR_SCINTILLA_A) $(SCI_VENDOR_LEXILLA_A) $(SCI_VENDOR_TERMBOX_A) + +$(SCI_VENDOR_SCINTILLA_H): + mkdir -p $(SCINTILLA_VENDOR) + curl -fsSL $(SCINTILLA_URL) | tar xzf - -C $(SCINTILLA_VENDOR) -jerboa_scintilla_shim.$(SHLIB_EXT): $(SCI_DIR)/jerboa_scintilla_shim.c - @test -d $(SCINTILLA_VENDOR) || \ - { echo "ERROR: SCINTILLA_VENDOR='$(SCINTILLA_VENDOR)' not found. Populate it from the jerboa-scintilla dependency or set SCINTILLA_VENDOR."; exit 1; } +$(SCI_VENDOR_LEXILLA_H): + mkdir -p $(SCINTILLA_VENDOR) + curl -fsSL $(LEXILLA_URL) | tar xzf - -C $(SCINTILLA_VENDOR) + +$(SCI_VENDOR_TB_H): $(SCI_VENDOR_SCINTILLA_H) + git clone --depth 1 $(SCINTILLA_TB_URL) $(SCI_VENDOR_TB_DIR) + +$(SCI_VENDOR_TERMBOX_H): $(SCI_VENDOR_TB_H) + git clone --depth 1 $(TERMBOX_URL) $(SCI_VENDOR_TERMBOX_DIR) + +$(SCI_VENDOR_TERMBOX_A): $(SCI_VENDOR_TERMBOX_H) + $(MAKE) -C $(SCI_VENDOR_TERMBOX_DIR) FLAGS+="-fPIC" + +$(SCI_VENDOR_SCINTILLA_A): $(SCI_VENDOR_SCINTILLA_H) $(SCI_VENDOR_TB_H) $(SCI_VENDOR_TERMBOX_A) + $(MAKE) -C $(SCI_VENDOR_TB_DIR) EXTRA_FLAGS="-fPIC" + +$(SCI_VENDOR_LEXILLA_A): $(SCI_VENDOR_LEXILLA_H) $(SCI_VENDOR_SCINTILLA_H) + $(MAKE) -C $(SCI_VENDOR_LEXILLA_DIR)/src + +scintilla-vendor-clean: + rm -rf $(SCINTILLA_VENDOR) + +jerboa_scintilla_shim.$(SHLIB_EXT): $(SCI_DIR)/jerboa_scintilla_shim.c $(SCI_VENDOR_SCINTILLA_A) $(SCI_VENDOR_LEXILLA_A) $(SCI_VENDOR_TERMBOX_A) gcc $(SHLIB_FLAGS) -O2 \ -I$(SCINTILLA_VENDOR)/scintilla/include \ -I$(SCINTILLA_VENDOR)/scintilla/src \ @@ -514,25 +606,26 @@ jerboa_scintilla_shim.$(SHLIB_EXT): $(SCI_DIR)/jerboa_scintilla_shim.c -I$(SCINTILLA_VENDOR)/lexilla/include \ -o jerboa_scintilla_shim.$(SHLIB_EXT) \ $(SCI_DIR)/jerboa_scintilla_shim.c \ - -Wl,--whole-archive \ - $(SCINTILLA_VENDOR)/scintilla/bin/scintilla.a \ - $(SCINTILLA_VENDOR)/lexilla/bin/liblexilla.a \ - $(SCINTILLA_VENDOR)/scintilla/termbox/termbox_next/bin/termbox.a \ - -Wl,--no-whole-archive \ - -lstdc++ -lpthread -Wall + $(SCINTILLA_ARCHIVES) \ + $(SCINTILLA_STDLIBS) -Wall # pcre2 shim — copied from jerboa-pcre2 (already built there) PCRE2_DIR ?= $(JERBOA_PCRE2_ROOT) -pcre2_shim.$(SHLIB_EXT): $(PCRE2_DIR)/pcre2_shim.$(SHLIB_EXT) +jerboa_pcre2_shim.$(SHLIB_EXT): $(PCRE2_DIR)/jerboa_pcre2_shim.$(SHLIB_EXT) + cp $< $@ + +pcre2_shim.$(SHLIB_EXT): jerboa_pcre2_shim.$(SHLIB_EXT) cp $< $@ # TUI binary: embeds all Scheme code, links dynamically against system libs. # Shims must be in the same directory as the binary (jemacs-main.c sets JERBOA_SCINTILLA_LIB # and JERBOA_PCRE2_LIB to dirname(binary) when not already set in environment). -binary: build vterm_shim.$(SHLIB_EXT) jerboa_scintilla_shim.$(SHLIB_EXT) pcre2_shim.$(SHLIB_EXT) +binary: build vterm_shim.$(SHLIB_EXT) jerboa_scintilla_shim.$(SHLIB_EXT) jerboa_pcre2_shim.$(SHLIB_EXT) find vendor/jerboa-shell -name '*.wpo' -delete 2>/dev/null; true - $(SCHEME) $(LIBDIRS) --script build-binary.ss + JERBOA_PCRE2_DIR=$(JERBOA_PCRE2_LIBDIR) JERBOA_PCRE2_ROOT=$(JERBOA_PCRE2_ROOT) \ + JERBOA_SCINTILLA_DIR=$(JERBOA_SCINTILLA_LIBDIR) SCI_VENDOR_DIR=$(SCINTILLA_VENDOR) \ + $(SCHEME) $(LIBDIRS) --script build-binary.ss # ============================================================================= # Static binary builds (Podman-based, Alpine musl) @@ -548,7 +641,6 @@ PODMAN_RUN_FLAGS ?= # Dependency source directories (vendored clones) JERBOA_SRC ?= $(JERBOA) -GHERKIN_SRC ?= $(CURDIR)/vendor/gherkin-runtime JSH_SRC ?= $(JSH_ROOT) JSH_VENDOR_SRC ?= $(JSH_SRC)/vendor PCRE2_SRC ?= $(JERBOA_PCRE2_ROOT) @@ -596,7 +688,6 @@ podman-deps: check-podman --build-arg ARCH=$(ARCH) \ --build-arg CHEZ_COMMIT=$(CHEZ_COMMIT) \ --build-context jerboa-src=$(JERBOA_SRC) \ - --build-context gherkin-src=$(GHERKIN_SRC) \ --build-context jsh-src=$(JSH_SRC) \ --build-context pcre2-src=$(PCRE2_SRC) \ --build-context sci-src=$(SCI_SRC) \ @@ -721,7 +812,6 @@ build-jemacs-qt-static: check-root CHEZ_DIR=$(CHEZ_MUSL_DIR) \ JERBOA_DIR=/deps/jerboa/lib \ JSH_DIR=/deps/jsh/src \ - GHERKIN_DIR=/src/vendor/gherkin-runtime \ JERBOA_PCRE2_DIR=/deps/jerboa-pcre2 \ JERBOA_SCINTILLA_DIR=/deps/jerboa-scintilla/src \ JERBOA_QT_DIR=/deps/jerboa-qt \ @@ -735,7 +825,7 @@ build-jemacs-qt-static: check-root TREE_SITTER_QUERIES_OBJ=/tmp/jemacs-build/treesitter_queries.o \ PKG_CONFIG_PATH=/opt/qt6-static/lib/pkgconfig \ /opt/chez/bin/scheme \ - --libdirs lib:/deps/jerboa/lib:/deps/jsh/src:/deps/jsh/vendor/jerboa-coreutils/lib:/deps/jsh/vendor/jerboa-awk/lib:/deps/jsh/vendor/jerboa-sed/lib:/deps/jsh/vendor/jerboa-ssh/src:/deps/jsh/vendor/jerboa-sqlite/src:/deps/jsh/vendor/jerboa-crypto/src:/deps/jsh/vendor/jerboa-fuse/lib:/src/vendor/gherkin-runtime:/deps/jerboa-pcre2:/deps/jerboa-scintilla/src:/deps/jerboa-qt$(AWS_STATIC_LIBDIRS) \ + --libdirs lib:/deps/jerboa/lib:/deps/jsh/src:/deps/jsh/vendor/jerboa-coreutils/lib:/deps/jsh/vendor/jerboa-awk/lib:/deps/jsh/vendor/jerboa-sed/lib:/deps/jsh/vendor/jerboa-ssh/src:/deps/jsh/vendor/jerboa-sqlite/src:/deps/jsh/vendor/jerboa-crypto/src:/deps/jsh/vendor/jerboa-fuse/lib:/deps/jerboa-pcre2:/deps/jerboa-scintilla/src:/deps/jerboa-qt$(AWS_STATIC_LIBDIRS) \ --script build-binary-qt.ss linux-static-qt-podman: ensure-podman-deps @@ -850,13 +940,12 @@ build-jemacs-tui-static: check-root CHEZ_DIR=$(CHEZ_MUSL_DIR) \ JERBOA_DIR=/deps/jerboa/lib \ JSH_DIR=/deps/jsh/src \ - GHERKIN_DIR=/src/vendor/gherkin-runtime \ JERBOA_PCRE2_DIR=/deps/jerboa-pcre2 \ JERBOA_SCINTILLA_DIR=/deps/jerboa-scintilla/src \ SCI_VENDOR_DIR=/deps/sci-vendor \ JSH_COREUTILS_LIB=/deps/jsh/libjsh_coreutils.a \ /opt/chez/bin/scheme \ - --libdirs lib:/deps/jerboa/lib:/deps/jsh/src:/deps/jsh/vendor/jerboa-coreutils/lib:/deps/jsh/vendor/jerboa-awk/lib:/deps/jsh/vendor/jerboa-sed/lib:/deps/jsh/vendor/jerboa-ssh/src:/deps/jsh/vendor/jerboa-sqlite/src:/deps/jsh/vendor/jerboa-crypto/src:/deps/jsh/vendor/jerboa-fuse/lib:/src/vendor/gherkin-runtime:/deps/jerboa-pcre2:/deps/jerboa-scintilla/src \ + --libdirs lib:/deps/jerboa/lib:/deps/jsh/src:/deps/jsh/vendor/jerboa-coreutils/lib:/deps/jsh/vendor/jerboa-awk/lib:/deps/jsh/vendor/jerboa-sed/lib:/deps/jsh/vendor/jerboa-ssh/src:/deps/jsh/vendor/jerboa-sqlite/src:/deps/jsh/vendor/jerboa-crypto/src:/deps/jsh/vendor/jerboa-fuse/lib:/deps/jerboa-pcre2:/deps/jerboa-scintilla/src \ --script build-binary.ss linux-static-tui-podman: ensure-podman-deps @@ -929,8 +1018,6 @@ linux-tui-local: vendor-deps find $(MUSL_SCINTILLA) -name '*.so' -delete 2>/dev/null; true find $(MUSL_PCRE2) -name '*.so' -delete 2>/dev/null; true find $(MUSL_JSH_ROOT) -name '*.wpo' -delete 2>/dev/null; true - find vendor/gherkin-runtime -name '*.so' -delete 2>/dev/null; true - find vendor/gherkin-runtime -name '*.wpo' -delete 2>/dev/null; true find vendor/jerboa-shell -name '*.so' -delete 2>/dev/null; true find vendor/jerboa-shell -name '*.wpo' -delete 2>/dev/null; true @echo "Recompiling jerboa core + prelude..." @@ -979,12 +1066,11 @@ linux-tui-local: vendor-deps CHEZ_DIR=$(MUSL_CHEZ_DIR) \ JERBOA_DIR=$(MUSL_JERBOA)/lib \ JSH_DIR=$(MUSL_JSH) \ - GHERKIN_DIR=$(GHERKIN) \ JERBOA_PCRE2_DIR=$(MUSL_PCRE2) \ JERBOA_SCINTILLA_DIR=$(MUSL_SCINTILLA)/src \ SCI_VENDOR_DIR=$(MUSL_SCI_VENDOR) \ $(MUSL_SCHEME) \ - --libdirs lib:$(MUSL_JERBOA)/lib:$(MUSL_JSH):$(COREUTILS):$(JSH_AWK):$(JSH_SED):$(JERBOA_SSH):$(JERBOA_SQLITE):$(JERBOA_CRYPTO):$(JERBOA_FUSE):$(GHERKIN):$(MUSL_PCRE2):$(MUSL_SCINTILLA)/src \ + --libdirs lib:$(MUSL_JERBOA)/lib:$(MUSL_JSH):$(COREUTILS):$(JSH_AWK):$(JSH_SED):$(JERBOA_SSH):$(JERBOA_SQLITE):$(JERBOA_CRYPTO):$(JERBOA_FUSE):$(MUSL_PCRE2):$(MUSL_SCINTILLA)/src \ --script build-binary.ss @echo "" @echo "=== jemacs static TUI binary built ===" @@ -1024,8 +1110,6 @@ linux-qt-local: vendor-deps find $(MUSL_SCINTILLA) -name '*.so' -delete 2>/dev/null; true find $(MUSL_PCRE2) -name '*.so' -delete 2>/dev/null; true find $(MUSL_JSH_ROOT) -name '*.wpo' -delete 2>/dev/null; true - find vendor/gherkin-runtime -name '*.so' -delete 2>/dev/null; true - find vendor/gherkin-runtime -name '*.wpo' -delete 2>/dev/null; true find vendor/jerboa-shell -name '*.so' -delete 2>/dev/null; true find vendor/jerboa-shell -name '*.wpo' -delete 2>/dev/null; true find vendor/jerboa-ssl -name '*.so' -delete 2>/dev/null; true @@ -1117,7 +1201,6 @@ linux-qt-local: vendor-deps CHEZ_DIR=$(MUSL_CHEZ_DIR) \ JERBOA_DIR=$(MUSL_JERBOA)/lib \ JSH_DIR=$(MUSL_JSH) \ - GHERKIN_DIR=$(GHERKIN) \ JERBOA_PCRE2_DIR=$(MUSL_PCRE2) \ JERBOA_SCINTILLA_DIR=$(MUSL_SCINTILLA)/src \ JERBOA_QT_DIR=/tmp/jemacs-build/jerboa-qt \ @@ -1131,7 +1214,7 @@ linux-qt-local: vendor-deps TREE_SITTER_QUERIES_OBJ=/tmp/jemacs-build/treesitter_queries.o \ PKG_CONFIG_PATH=/opt/qt6-static/lib/pkgconfig \ $(MUSL_SCHEME) \ - --libdirs lib:$(MUSL_JERBOA)/lib:$(MUSL_JSH):$(COREUTILS):$(JSH_AWK):$(JSH_SED):$(JERBOA_SSH):$(JERBOA_SQLITE):$(JERBOA_CRYPTO):$(JERBOA_FUSE):$(GHERKIN):$(MUSL_PCRE2):$(MUSL_SCINTILLA)/src:/tmp/jemacs-build/jerboa-qt$(AWS_LOCAL_STATIC_LIBDIRS) \ + --libdirs lib:$(MUSL_JERBOA)/lib:$(MUSL_JSH):$(COREUTILS):$(JSH_AWK):$(JSH_SED):$(JERBOA_SSH):$(JERBOA_SQLITE):$(JERBOA_CRYPTO):$(JERBOA_FUSE):$(MUSL_PCRE2):$(MUSL_SCINTILLA)/src:/tmp/jemacs-build/jerboa-qt$(AWS_LOCAL_STATIC_LIBDIRS) \ --script build-binary-qt.ss @echo "" @echo "=== jemacs-qt static binary built ===" --- a/README.md +++ b/README.md @@ -21,7 +21,6 @@ The TUI backend runs in a terminal using Scintilla's text model. The Qt backend | Chez Scheme ≥ 9.6 | Scheme runtime | system | | jerboa | Gerbil-compat stdlib | `vendor/jerboa` | | jerboa-shell (jsh) | Shell interpreter | `vendor/jerboa-shell` | -| gherkin runtime | Scheme dialect runtime | `vendor/gherkin-runtime` | | jerboa-scintilla | Scintilla editor FFI | `vendor/jerboa-scintilla` | | jerboa-pcre2 | PCRE2 regex FFI | `vendor/jerboa-pcre2` | @@ -37,6 +36,13 @@ The TUI backend runs in a terminal using Scintilla's text model. The Qt backend All commands run from the project root. +### Jerboa build tools + +`make build` and `make binary` use project-local `./jerbuild` first, then +`.jerboa/bin`, then `../jerboa/dist`, then `PATH`, and download the matching +Jerboa release artifact if none are available. The editor still vendors and +builds its native Scheme/FFI dependencies under `vendor/`. + ### Vendor dependencies ```bash @@ -193,7 +199,6 @@ The Gerbil form `(with-output-to-string "" thunk)` is not valid in Chez. | `SCHEME` | `vendor/jerboa/.chez/bin/scheme` | Chez Scheme executable | | `JERBOA` | `vendor/jerboa` | jerboa checkout | | `JSH` | `vendor/jerboa-shell/src` | jsh source path | -| `GHERKIN` | `vendor/gherkin-runtime` | gherkin runtime path | Override on the command line: `make SCHEME=/usr/local/bin/chez build` --- a/build-binary-qt.ss +++ b/build-binary-qt.ss @@ -102,12 +102,10 @@ (define jerboa-dir (or (getenv "JERBOA_DIR") (repo-path "vendor/jerboa/lib"))) -(define gherkin-dir - (or (getenv "GHERKIN_DIR") - (repo-path "vendor/gherkin-runtime"))) (define jsh-dir (or (getenv "JSH_DIR") (repo-path "vendor/jerboa-shell/src"))) +(define jsh-root (path-parent jsh-dir)) (define pcre2-dir (or (getenv "JERBOA_PCRE2_DIR") (repo-path "vendor/jerboa-pcre2"))) @@ -166,7 +164,6 @@ (printf "Chez dir: ~a~n" chez-dir) (printf "Jerboa dir: ~a~n" jerboa-dir) -(printf "Gherkin dir: ~a~n" gherkin-dir) (printf "jsh dir: ~a~n" jsh-dir) (printf "pcre2 dir: ~a~n" pcre2-dir) (printf "Sci dir: ~a~n" sci-dir) @@ -230,12 +227,15 @@ (format "~a/jerboa/~a.so" jerboa-dir (symbol-path tail)))) ((jsh) (format "~a/jsh/~a.so" jsh-dir (symbol-path tail))) + ((jerboa-awk) + (format "~a/vendor/jerboa-awk/lib/jerboa-awk/~a.so" jsh-root (symbol-path tail))) + ((sed) + (format "~a/vendor/jerboa-sed/lib/sed/~a.so" jsh-root (symbol-path tail))) ((compat) (if (and (pair? tail) (eq? (car tail) 'gambit)) (format "~a/compat/gambit.so" jsh-dir) - (format "~a/compat/~a.so" gherkin-dir (symbol-path tail)))) - ((runtime) - (format "~a/runtime/~a.so" gherkin-dir (symbol-path tail))) + #f)) + ((runtime) #f) ((jerboa-pcre2) (format "~a/jerboa-pcre2/~a.so" pcre2-dir (symbol-path tail))) ((jerboa-scintilla) --- a/build-binary.ss +++ b/build-binary.ss @@ -82,24 +82,52 @@ (define jerboa-dir (or (getenv "JERBOA_DIR") (repo-path "vendor/jerboa/lib"))) -(define gherkin-dir - (or (getenv "GHERKIN_DIR") - (repo-path "vendor/gherkin-runtime"))) (define jsh-dir (or (getenv "JSH_DIR") (repo-path "vendor/jerboa-shell/src"))) +(define jsh-root (path-parent jsh-dir)) (define pcre2-dir (or (getenv "JERBOA_PCRE2_DIR") + (repo-path "vendor/jerboa-pcre2/lib"))) +(define pcre2-root + (or (getenv "JERBOA_PCRE2_ROOT") (repo-path "vendor/jerboa-pcre2"))) (define sci-dir (or (getenv "JERBOA_SCINTILLA_DIR") - (repo-path "vendor/jerboa-scintilla/src"))) + (repo-path "vendor/jerboa-scintilla/lib"))) ;; Scintilla vendor dir: contains scintilla.a, liblexilla.a, termbox.a and the ;; C header files needed to compile jerboa_scintilla_shim.c. (define sci-vendor-dir (or (getenv "SCI_VENDOR_DIR") (repo-path "vendor/jerboa-scintilla/vendor"))) +(define (first-existing-file paths) + (let loop ((rest paths)) + (cond + ((null? rest) #f) + ((file-exists? (car rest)) (car rest)) + (else (loop (cdr rest)))))) + +(define (require-existing-file label paths) + (or (first-existing-file paths) + (begin + (printf "Error: ~a not found. Tried:~n" label) + (for-each (lambda (path) (printf " ~a~n" path)) paths) + (exit 1)))) + +(define libcoreutils-c + (require-existing-file + "libcoreutils.c" + (list (format "~a/libcoreutils.c" jsh-root) + (format "~a/vendor/jerboa-coreutils/support/libcoreutils.c" jsh-root) + (format "~a/patches/libcoreutils.c" jsh-root)))) + +(define machine-name (symbol->string (machine-type))) +(define darwin? + (let ((n (string-length machine-name))) + (and (>= n 3) + (string=? (substring machine-name (- n 3) n) "osx")))) + ;; Static build detection (define jemacs-static? (let ((v (getenv "JEMACS_STATIC"))) @@ -122,9 +150,9 @@ (printf "Chez dir: ~a~n" chez-dir) (printf "Jerboa dir: ~a~n" jerboa-dir) -(printf "Gherkin dir: ~a~n" gherkin-dir) (printf "jsh dir: ~a~n" jsh-dir) (printf "pcre2 dir: ~a~n" pcre2-dir) +(printf "pcre2 root: ~a~n" pcre2-root) (printf "Sci dir: ~a~n" sci-dir) (when jemacs-static? (printf "Sci vendor: ~a~n" sci-vendor-dir) @@ -179,12 +207,15 @@ (format "~a/jerboa/~a.so" jerboa-dir (symbol-path tail)))) ((jsh) (format "~a/jsh/~a.so" jsh-dir (symbol-path tail))) + ((jerboa-awk) + (format "~a/vendor/jerboa-awk/lib/jerboa-awk/~a.so" jsh-root (symbol-path tail))) + ((sed) + (format "~a/vendor/jerboa-sed/lib/sed/~a.so" jsh-root (symbol-path tail))) ((compat) (if (and (pair? tail) (eq? (car tail) 'gambit)) (format "~a/compat/gambit.so" jsh-dir) - (format "~a/compat/~a.so" gherkin-dir (symbol-path tail)))) - ((runtime) - (format "~a/runtime/~a.so" gherkin-dir (symbol-path tail))) + #f)) + ((runtime) #f) ((jerboa-pcre2) (format "~a/jerboa-pcre2/~a.so" pcre2-dir (symbol-path tail))) ((jerboa-scintilla) @@ -235,8 +266,8 @@ ;; pcre2 shim (let* ((pcre2-cflags (shell-output "pkg-config --cflags libpcre2-8" "-I/usr/include")) - (cmd (format "gcc -c -O2 -o jemacs-pcre2-shim.o ~a/pcre2_shim.c ~a -Wall 2>&1" - pcre2-dir pcre2-cflags))) + (cmd (format "gcc -c -O2 -o jemacs-pcre2-shim.o ~a/jerboa_pcre2_shim.c ~a -Wall 2>&1" + pcre2-root pcre2-cflags))) (unless (= 0 (system cmd)) (display "Error: pcre2 shim compilation failed\n") (exit 1))) @@ -244,17 +275,15 @@ ;; Static-only C sources (when jemacs-static? ;; jsh FFI shim - (let* ((jsh-root (path-parent jsh-dir)) - (cmd (format "gcc -c -O2 -o jemacs-jsh-ffi.o ~a/ffi-shim.c -Wall 2>&1" + (let* ((cmd (format "gcc -c -O2 -o jemacs-jsh-ffi.o ~a/ffi-shim.c -Wall 2>&1" jsh-root))) (unless (= 0 (system cmd)) (display "Error: jsh ffi-shim.c compilation failed\n") (exit 1))) ;; libcoreutils.c (terminal/raw-mode symbols) - (let* ((jsh-root (path-parent jsh-dir)) - (cmd (format "gcc -c -O2 -o jemacs-libcoreutils.o ~a/libcoreutils.c -Wall 2>&1" - jsh-root))) + (let* ((cmd (format "gcc -c -O2 -o jemacs-libcoreutils.o ~a -Wall 2>&1" + libcoreutils-c))) (unless (= 0 (system cmd)) (display "Error: libcoreutils.c compilation failed\n") (exit 1))) @@ -268,8 +297,7 @@ ;; embed-crypto. Older jsh trees had embed-crypto.c; newer ones use ;; libjerboa_native. If neither is available, compile explicit failing stubs ;; so non-embed editor features still link and encrypted embed calls fail. - (let* ((jsh-root (path-parent jsh-dir)) - (embed-src (format "~a/embed-crypto.c" jsh-root)) + (let* ((embed-src (format "~a/embed-crypto.c" jsh-root)) (fallback-src "support/jsh_embed_crypto_stubs.c") (src (if (file-exists? embed-src) embed-src fallback-src)) (cmd (format "gcc -c -O2 -o jemacs-embed-crypto.o ~a -I~a -Wall 2>&1" @@ -331,7 +359,7 @@ ;; Generate FFI symbol registration table ;; Scans Scheme sources for foreign-procedure calls, generates tui_static_symbols.c - (let* ((ffi-path (format "~a/jerboa-pcre2/ffi.ss" pcre2-dir)) + (let* ((ffi-path (format "~a/src/jerboa-pcre2/ffi.ss" pcre2-root)) (include-dir chez-dir) (gen-cmd (format @@ -389,23 +417,23 @@ echo OK" (display "Error: repl_shim.c (dynamic) compilation failed\n") (exit 1))) ;; jsh FFI shim (ffi_file_type, ffi_*, etc.) - (let* ((jsh-root (path-parent jsh-dir)) - (cmd (format "gcc -c -O2 -o jemacs-jsh-ffi.o ~a/ffi-shim.c -Wall 2>&1" + (let* ((cmd (format "gcc -c -O2 -o jemacs-jsh-ffi.o ~a/ffi-shim.c -Wall 2>&1" jsh-root))) (unless (= 0 (system cmd)) (display "Error: jsh ffi-shim.c (dynamic) compilation failed\n") (exit 1))) ;; libcoreutils (coreutils_raw_mode_*, coreutils_terminal_*, etc.) - (let* ((jsh-root (path-parent jsh-dir)) - (cmd (format "gcc -c -O2 -o jemacs-libcoreutils.o ~a/libcoreutils.c -Wall 2>&1" - jsh-root))) + (let* ((cmd (format "gcc -c -O2 -o jemacs-libcoreutils.o ~a -Wall 2>&1" + libcoreutils-c))) (unless (= 0 (system cmd)) (display "Error: libcoreutils.c (dynamic) compilation failed\n") (exit 1))) ;; embed-crypto (embed_* symbols) - (let* ((jsh-root (path-parent jsh-dir)) - (cmd (format "gcc -c -O2 -o jemacs-embed-crypto.o ~a/embed-crypto.c -I~a -Wall 2>&1" - jsh-root jsh-root))) + (let* ((embed-src (format "~a/embed-crypto.c" jsh-root)) + (fallback-src "support/jsh_embed_crypto_stubs.c") + (src (if (file-exists? embed-src) embed-src fallback-src)) + (cmd (format "gcc -c -O2 -o jemacs-embed-crypto.o ~a -I~a -Wall 2>&1" + src jsh-root))) (unless (= 0 (system cmd)) (display "Error: embed-crypto.c (dynamic) compilation failed\n") (exit 1))) @@ -496,6 +524,7 @@ tui_static_symbols.o \ ;; Chez's foreign-procedure finds them via dlopen(NULL)/dlopen(""). (let* ((pcre2-libs (shell-output "pkg-config --libs libpcre2-8" "-lpcre2-8")) (ncurses-libs (shell-output "pkg-config --libs ncurses" "-lncurses")) + (iconv-libs (if darwin? "-liconv" "")) (cmd (format "gcc -rdynamic -o jemacs \ jemacs-main.o jemacs-pcre2-shim.o jemacs-repl-shim.o \ jemacs-jsh-ffi.o jemacs-libcoreutils.o jemacs-embed-crypto.o \ @@ -503,8 +532,8 @@ jemacs-ssh-agent-stub.o jemacs-jsh-coreutils-stubs.o \ jemacs-tls-stubs.o \ -L~a -lkernel -llz4 -lz \ ~a ~a \ --lm -ldl -lpthread 2>&1" - chez-dir pcre2-libs ncurses-libs))) +-lm -ldl -lpthread ~a 2>&1" + chez-dir pcre2-libs ncurses-libs iconv-libs))) (printf " ~a~n" cmd) (unless (= 0 (system cmd)) (display "Error: Dynamic link failed\n") --- a/jemacs-main.c +++ b/jemacs-main.c @@ -30,23 +30,70 @@ #include <stdlib.h> #include <string.h> #include <stdio.h> +#include <stdint.h> +#include <errno.h> #include <unistd.h> #include <libgen.h> #include <sys/mman.h> #include <sys/stat.h> +#ifdef __APPLE__ +#include <mach-o/dyld.h> +#endif #include "scheme.h" #include "jemacs_program.h" /* jemacs_program_data[], jemacs_program_size */ #include "jemacs_petite_boot.h" /* petite_boot_data[], petite_boot_size */ #include "jemacs_scheme_boot.h" /* scheme_boot_data[], scheme_boot_size */ #include "jemacs_jemacs_boot.h" /* jemacs_boot_data[], jemacs_boot_size */ +static int write_all(int fd, const unsigned char *data, unsigned int size) { + const unsigned char *cursor = data; + size_t remaining = size; + + while (remaining > 0) { + ssize_t written = write(fd, cursor, remaining); + if (written < 0) { + if (errno == EINTR) + continue; + return -1; + } + if (written == 0) + return -1; + cursor += written; + remaining -= (size_t)written; + } + + return 0; +} + int main(int argc, char *argv[]) { /* Resolve real executable path */ char exe_buf[4096]; char exe_dir[4096]; +#ifdef __APPLE__ + uint32_t exe_len = sizeof(exe_buf); + int have_exe = (_NSGetExecutablePath(exe_buf, &exe_len) == 0); + if (have_exe) { + char real_buf[4096]; + char *resolved = realpath(exe_buf, real_buf); + if (resolved) { + strncpy(exe_buf, resolved, sizeof(exe_buf) - 1); + exe_buf[sizeof(exe_buf) - 1] = '\0'; + } + } +#elif defined(__FreeBSD__) + ssize_t len = readlink("/proc/curproc/file", exe_buf, sizeof(exe_buf) - 1); + int have_exe = (len > 0); + if (have_exe) { + exe_buf[len] = '\0'; + } +#else ssize_t len = readlink("/proc/self/exe", exe_buf, sizeof(exe_buf) - 1); - if (len > 0) { + int have_exe = (len > 0); + if (have_exe) { exe_buf[len] = '\0'; + } +#endif + if (have_exe) { setenv("JEMACS_EXE", exe_buf, 1); /* dirname() may modify its argument, use a copy */ strncpy(exe_dir, exe_buf, sizeof(exe_dir) - 1); @@ -59,19 +106,36 @@ int main(int argc, char *argv[]) { setenv("JERBOA_PCRE2_LIB", dir, 0); } - /* Create memfd for embedded program .so */ + /* Create a file for the embedded program .so. Linux can avoid touching + * disk via memfd; other hosts use a private temporary file. */ + char prog_path[4096]; +#ifdef __linux__ int fd = memfd_create("jemacs-program", MFD_CLOEXEC); if (fd < 0) { perror("memfd_create"); return 1; } - if (write(fd, jemacs_program_data, jemacs_program_size) != (ssize_t)jemacs_program_size) { - perror("write memfd"); +#else + const char *tmpdir = getenv("TMPDIR"); + if (!tmpdir || !tmpdir[0]) tmpdir = "/tmp"; + snprintf(prog_path, sizeof(prog_path), "%s/jemacs-program-XXXXXX", tmpdir); + int fd = mkstemp(prog_path); + if (fd < 0) { + perror("mkstemp"); + return 1; + } +#endif + if (write_all(fd, jemacs_program_data, jemacs_program_size) != 0) { + perror("write embedded program"); close(fd); +#ifndef __linux__ + unlink(prog_path); +#endif return 1; } - char prog_path[64]; +#ifdef __linux__ snprintf(prog_path, sizeof(prog_path), "/proc/self/fd/%d", fd); +#endif /* Initialize Chez Scheme */ Sscheme_init(NULL); @@ -106,6 +170,9 @@ int main(int argc, char *argv[]) { int status = Sscheme_script(prog_path, argc, (const char **)argv); close(fd); +#ifndef __linux__ + unlink(prog_path); +#endif Sscheme_deinit(); return status; } --- a/lib/jerboa-emacs/qt/commands-parity5.sls +++ b/lib/jerboa-emacs/qt/commands-parity5.sls @@ -637,8 +637,7 @@ (echo-message! (app-state-echo app) "Frame raised"))) (def (cmd-rotate-window app) (execute-command! app 'other-window)) - (def (cmd-run-scheme app) - (execute-command! app 'run-chez)) + (def (cmd-run-scheme app) (execute-command! app 'run-chez)) (def (cmd-shell-here app) (execute-command! app 'shell)) (def (cmd-whitespace-report app) (let* ([fr (app-state-frame app)] --- a/lib/jerboa-emacs/qt/commands-shell.sls +++ b/lib/jerboa-emacs/qt/commands-shell.sls @@ -2039,9 +2039,7 @@ #\#))] [(memq lang - '(scheme - lisp - )) + '(scheme lisp)) (or (string-prefix? "(def " trimmed) --- a/src/jerboa-emacs/core.ss +++ b/src/jerboa-emacs/core.ss @@ -1991,9 +1991,6 @@ (lambda () (jemacs-log! "ensure-eval!: Chez Scheme eval environment ready"))))) -;; Backward compatibility alias -(def ensure-eval! ensure-eval!) - (def (eval-expression-string str) "In-process eval: read+eval an expression string, capture output. Returns (values result-string error?). new file mode 100755 --- /dev/null +++ b/support/ensure-jerboa.sh @@ -0,0 +1,121 @@ +#!/bin/sh +# Bootstrap a project-local Jerboa toolchain from SourceHut release artifacts. +# +# Usage: +# support/ensure-jerboa.sh v0.2.0 .jerboa/bin +# +# Override the artifact location with: +# JERBOA_RELEASE_BASE=https://example.org/releases/v0.2.0 +# or the SourceHut repo with: +# JERBOA_RELEASE_REPO=~lisp/jerboa +# For testing or unusual hosts, override target detection with: +# JERBOA_RELEASE_TARGET=macos-arm64 + +set -eu + +usage() { + echo "Usage: $0 VERSION [BINDIR]" >&2 +} + +[ "${1:-}" ] || { usage; exit 2; } + +version=$1 +bindir=${2:-.jerboa/bin} +repo=${JERBOA_RELEASE_REPO:-~lisp/jerboa} +origin=${JERBOA_RELEASE_ORIGIN:-https://git.sr.ht} + +if [ "${JERBOA_RELEASE_TARGET:-}" ]; then + target=$JERBOA_RELEASE_TARGET +else + os=$(uname -s) + arch=$(uname -m) + case "$os-$arch" in + Darwin-arm64) target=macos-arm64 ;; + Linux-x86_64|Linux-amd64) target=linux-amd64 ;; + Linux-aarch64|Linux-arm64) target=linux-arm64 ;; + FreeBSD-amd64|FreeBSD-x86_64) target=freebsd-amd64 ;; + *) + echo "ERROR: unsupported platform for Jerboa release artifacts: $os $arch" >&2 + echo " set JERBUILD=/path/to/jerbuild or build Jerboa locally for this host" >&2 + exit 1 + ;; + esac +fi + +case "$target" in + macos-arm64|linux-amd64|linux-arm64|freebsd-amd64) ;; + *) + echo "ERROR: unsupported release target: $target" >&2 + exit 1 + ;; +esac + +file="jerboa-${version}-${target}.tar.gz" +base=${JERBOA_RELEASE_BASE:-${origin}/${repo}/refs/download/${version}} +url="${base%/}/${file}" +sum_url="${url}.sha256" + +download() { + src=$1 + dst=$2 + if command -v curl >/dev/null 2>&1; then + curl -fsSL "$src" -o "$dst" + elif command -v fetch >/dev/null 2>&1; then + fetch -q -o "$dst" "$src" + elif command -v wget >/dev/null 2>&1; then + wget -q -O "$dst" "$src" + else + echo "ERROR: need curl, fetch, or wget to download Jerboa" >&2 + exit 1 + fi +} + +sha256_file() { + path=$1 + if command -v sha256sum >/dev/null 2>&1; then + sha256sum "$path" | awk '{print $1}' + elif command -v shasum >/dev/null 2>&1; then + shasum -a 256 "$path" | awk '{print $1}' + elif command -v sha256 >/dev/null 2>&1; then + sha256 -q "$path" + else + echo "ERROR: need sha256sum, shasum, or sha256" >&2 + exit 1 + fi +} + +tmp=$(mktemp -d "${TMPDIR:-/tmp}/jerboa-bootstrap.XXXXXX") +trap 'rm -rf "$tmp"' EXIT HUP INT TERM + +archive="$tmp/$file" +sum_file="$tmp/$file.sha256" + +echo "fetching $url" +download "$url" "$archive" +download "$sum_url" "$sum_file" + +expected=$(awk '{print $1; exit}' "$sum_file") +actual=$(sha256_file "$archive") +if [ "$expected" != "$actual" ]; then + echo "ERROR: checksum mismatch for $file" >&2 + echo "expected: $expected" >&2 + echo "actual: $actual" >&2 + exit 1 +fi + +mkdir -p "$tmp/extract" +tar -xzf "$archive" -C "$tmp/extract" +root="$tmp/extract/jerboa-${version}-${target}" +[ -x "$root/bin/jerboa" ] || { + echo "ERROR: archive did not contain bin/jerboa" >&2 + exit 1 +} + +mkdir -p "$bindir" +cp "$root/bin/jerboa" "$bindir/jerboa" +chmod 0755 "$bindir/jerboa" +for link in jmcp jlsp jerbuild jpkg; do + ln -sf jerboa "$bindir/$link" +done + +echo "installed $bindir/{jerboa,jmcp,jlsp,jerbuild,jpkg}" --- a/support/static-precompile-deps.ss +++ b/support/static-precompile-deps.ss @@ -14,12 +14,6 @@ (std misc thread) (std os path) (std os signal) - (compat types) - (compat gambit-compat) - (runtime util) - (runtime table) - (runtime c3) - (runtime mop) (compat gambit) (jsh ffi) (jsh static-compat) --- a/vendor/jerboa-https +++ b/vendor/jerboa-https @@ -1 +1 @@ -Subproject commit 7f3c000355c97167dd3428a025168f9ba5a26a5c +Subproject commit 3bc7a40adcade47a776501ca9447cd501d63ad09 --- a/vendor/jerboa-scintilla +++ b/vendor/jerboa-scintilla @@ -1 +1 @@ -Subproject commit 4642655e00ddefbd4c4bf40d033d6e0587d9f085 +Subproject commit 96745c5ea69c95f1c4fa2ce80f43e9cdf59a55a6