Stop mutating source libs for portable builds
ober
0934f445c64e7b2d8d5076181e9486493f3009df
--- a/.gitignore +++ b/.gitignore @@ -3,6 +3,7 @@ *.tarm64osx /jcode .jerbuild-hashes +.build/ jcode.json # Vendored dependencies cloned at build time by `make vendor-deps` --- a/Makefile +++ b/Makefile @@ -2,6 +2,7 @@ JERBOA_HOME ?= $(HOME)/mine/jerboa SCHEME ?= $(JERBOA_HOME)/.chez/bin/scheme LIBDIRS = --libdirs $(JERBOA_HOME)/lib:./lib:vendor/chez-sqlite/src:vendor/jerboa-websearch/src JERBUILD = $(SCHEME) --libdirs $(JERBOA_HOME)/lib --script $(JERBOA_HOME)/jerbuild.ss +FREEBSD_AMD64_CC ?= $(JERBOA_HOME)/support/cross-cc-freebsd-amd64 # Fail early with a clear pointer if the jerboa-local Chez build is missing. ifeq ($(wildcard $(SCHEME)),) @@ -323,14 +324,13 @@ test-linux: test-linux-amd64 # # Prereqs (set up once): # - cd $(JERBOA_HOME) && make binary (builds .chez-cross-ta6fb/) -# - FreeBSD sysroot at ~/freebsd-sysroot (extracted from base.txz of -# a FreeBSD 14.x release: tar xJf base.txz ./usr/include ./usr/lib ./lib) -# - x86_64-unknown-freebsd14-clang on PATH (wrapper at ~/.local/bin/) +# - 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 x86_64-unknown-freebsd14-clang >/dev/null 2>&1 || { \ - echo "ERROR: x86_64-unknown-freebsd14-clang not on PATH" >&2; \ + @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 || { \ @@ -340,7 +340,7 @@ freebsd-amd64: gen @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) $(SCHEME) -q --libdirs "$(XC_LIBDIRS)" --script build-jcode-freebsd-cross.ss + JERBOA_HOME=$(JERBOA_HOME) CROSS_CC="$(FREEBSD_AMD64_CC)" $(SCHEME) -q --libdirs "$(XC_LIBDIRS)" --script build-jcode-freebsd-cross.ss # Friendly aliases. jcode-freebsd-amd64: freebsd-amd64 --- a/build-jcode-cross.ss +++ b/build-jcode-cross.ss @@ -195,65 +195,46 @@ (printf "~n") -;; ── Step 0.5: Patch load-shared-object in libraries for static linking ───── -;; In a static binary, dlopen is stubbed so any (load-shared-object "libfoo.so") -;; raises. Patch all .sls files (jerboa stdlib + vendor + project) to replace -;; the form with (void), matching what build-jcode-musl.ss does. Patches are -;; reverted at end of script via `git checkout`. - -(printf "==> [0.5/6] patching load-shared-object in libraries~n") -(define lso-patch-cmd - (string-append - "perl -i -0777 -pe 's/" - "\\(load-shared-object(?=\\s)" - "(?:[^()\"]++|\"(?:\\\\.|[^\"\\\\])*+\"|" - "(?<bal>\\((?:[^()\"]++|\"(?:\\\\.|[^\"\\\\])*+\"|(?&bal))*+\\))" - ")*+\\)/(void)/g'")) - -(define jerboa-lib-dir (format "~a/lib" jerboa-home)) -(system (format "find '~a' -name '*.sls' -exec ~a {} +" jerboa-lib-dir lso-patch-cmd)) -(system (format "find vendor/chez-sqlite -name '*.sls' -exec ~a {} +" lso-patch-cmd)) -(when (file-directory? "vendor/jerboa-websearch") - (system (format "find vendor/jerboa-websearch -name '*.sls' -exec ~a {} +" lso-patch-cmd))) -(when (file-directory? "lib") - (system (format "find lib -name '*.sls' -exec ~a {} +" lso-patch-cmd))) - -;; Delete stale .so files so they get recompiled with the patches. -(system (format "find '~a' -name '*.so' -delete 2>/dev/null" jerboa-lib-dir)) -(system "find vendor/chez-sqlite -name '*.so' -delete 2>/dev/null") -(system "find vendor/jerboa-websearch -name '*.so' -delete 2>/dev/null") -(system "find lib -name '*.so' -delete 2>/dev/null") - -(define (restore-patched-files!) - ;; Only restore .sls files — step 0.5 only patches .sls (never .ss), so a - ;; broad `git checkout -- .` would clobber unrelated .ss edits like vendor - ;; bug fixes that have to apply before compile-whole-program runs. - (printf "~n==> [cleanup] restoring patched .sls files via git~n") - (system (format "cd '~a' && git ls-files -z -- '*.sls' | xargs -0 git checkout -- 2>/dev/null" jerboa-home)) - (system "git ls-files -z -- 'lib/jcode/*.sls' | xargs -0 git checkout -- 2>/dev/null") - (system "cd vendor/chez-sqlite && git ls-files -z -- 'src/*.sls' | xargs -0 git checkout -- 2>/dev/null") - (when (file-directory? "vendor/jerboa-websearch") - (system "cd vendor/jerboa-websearch && git ls-files -z -- '*.sls' | xargs -0 git checkout -- 2>/dev/null"))) +;; ── Step 0.5: isolate cross-compiled objects ─────────────────────────────── +;; Never patch source libraries in-place. Chez xpatch can compile target +;; objects while `library-directories` maps source directories to a separate +;; writable object directory. + +(define obj-dir (format ".build/~a-obj" output)) +(define entry-so (format "~a/program.so" obj-dir)) +(define entry-wpo (format "~a/program.wpo" obj-dir)) + +(define (prepare-obj-dir!) + (system (format "rm -rf '~a'" obj-dir)) + (system (format "mkdir -p '~a'" obj-dir))) + +(define (cleanup!) + (system (format "rm -rf '~a'" obj-dir))) + +(prepare-obj-dir!) ;; ── Stage 1: load xpatch (target=ta6le emit mode) ────────────────────────── (define orig-libdirs (library-directories)) (printf "==> [1/6] loading xpatch (compiler -> ~a emit mode)~n" chez-machine) (load xpatch) -(library-directories orig-libdirs) +(library-directories + (map (lambda (pair) + (cons (if (pair? pair) (car pair) pair) obj-dir)) + orig-libdirs)) (compile-imported-libraries #t) (generate-wpo-files #t) ;; ── Stage 2: compile-program main-binary.ss ──────────────────────────────── -(printf "==> [2/6] compile-program ~a~n" entry-script) -(guard (e [#t (restore-patched-files!) (raise e)]) - (compile-program entry-script)) +(printf "==> [2/6] compile-program ~a -> ~a~n" entry-script entry-so) +(guard (e [#t (cleanup!) (raise e)]) + (compile-program entry-script entry-so)) ;; ── Stage 3: compile-whole-program → wpo .so ─────────────────────────────── (define wpo-output (string-append output ".wp.so")) -(printf "==> [3/6] compile-whole-program main-binary.wpo -> ~a~n" wpo-output) -(guard (e [#t (restore-patched-files!) (raise e)]) - (compile-whole-program "main-binary.wpo" wpo-output #t)) +(printf "==> [3/6] compile-whole-program ~a -> ~a~n" entry-wpo wpo-output) +(guard (e [#t (cleanup!) (raise e)]) + (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) @@ -545,17 +526,11 @@ (printf " ~a~n" link-cmd) (let ([rc (system link-cmd)]) (unless (zero? rc) - (restore-patched-files!) + (cleanup!) (error 'build-jcode-cross "cross-link failed" rc))) -;; ── Cleanup: restore patched files ────────────────────────────────────────── -(restore-patched-files!) - -;; Clean up intermediate compile-program outputs so the next dev cycle on -;; host scheme doesn't pick up cross-flavored .so files. -(for-each (lambda (f) - (when (file-exists? f) (delete-file f))) - '("main-binary.so" "main-binary.wpo")) +;; ── Cleanup: remove isolated cross objects ───────────────────────────────── +(cleanup!) (printf "~n=== Build complete: ~a ===~n" output) (system (format "ls -lh ~a" output)) --- a/build-jcode-freebsd-cross.ss +++ b/build-jcode-freebsd-cross.ss @@ -8,7 +8,7 @@ ;;; FreeBSD analogue of build-jcode-cross.ss. Uses: ;;; - $JERBOA_HOME/.chez-cross-ta6fb/ — cross-built Chez install (FreeBSD) ;;; - $JERBOA_HOME/build/chez/xc-ta6fb/s/xpatch — host compiler → ta6fb emit -;;; - x86_64-unknown-freebsd14-clang — macOS clang+lld with FreeBSD sysroot +;;; - $JERBOA_HOME/support/cross-cc-freebsd-amd64 — macOS clang+lld wrapper ;;; ;;; Produces: jcode-freebsd-amd64 (dynamic FreeBSD x86_64 ELF; depends on ;;; libc.so.7, libm.so, libthr.so, libutil.so on the target host). @@ -26,7 +26,8 @@ (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 cross-cc (or (getenv "CROSS_CC") + (format "~a/support/cross-cc-freebsd-amd64" jerboa-home))) (define output "jcode-freebsd-amd64") (define entry-script "main-binary.ss") @@ -144,10 +145,9 @@ cargo-features)] ;; cc-rs needs LLVM's llvm-ar (not Apple's /usr/bin/ar) and the ;; FreeBSD clang wrapper. Forward these to the cargo invocation. - [cc-env (string-append - "CARGO_TARGET_X86_64_UNKNOWN_FREEBSD_LINKER=x86_64-unknown-freebsd14-clang " - "CC_x86_64_unknown_freebsd=x86_64-unknown-freebsd14-clang " - "AR_x86_64_unknown_freebsd=/opt/homebrew/opt/llvm/bin/llvm-ar ")] + [cc-env (format + "CARGO_TARGET_X86_64_UNKNOWN_FREEBSD_LINKER='~a' CC_x86_64_unknown_freebsd='~a' AR_x86_64_unknown_freebsd=/opt/homebrew/opt/llvm/bin/llvm-ar " + cross-cc cross-cc)] [via-rustup (and rustup-bin-dir (format "cd '~a' && env ~aPATH='~a':$PATH RUSTC='~a/rustc' '~a/cargo' ~a" @@ -159,8 +159,8 @@ (error 'build-jcode-freebsd-cross (string-append "failed to build jerboa-native-rs for x86_64-unknown-freebsd. " - "Required: `rustup target add x86_64-unknown-freebsd`, plus the " - "x86_64-unknown-freebsd14-clang wrapper on PATH and " + "Required: `rustup target add x86_64-unknown-freebsd`, plus " + cross-cc " and " "/opt/homebrew/opt/llvm/bin/llvm-ar from the LLVM Homebrew formula."))) (unless (file-exists? jerboa-native-a) (error 'build-jcode-freebsd-cross "cargo succeeded but .a missing" jerboa-native-a)) @@ -183,65 +183,46 @@ (printf "~n") -;; ── Step 0.5: Patch load-shared-object in libraries for static linking ───── -;; In a static binary, dlopen is stubbed so any (load-shared-object "libfoo.so") -;; raises. Patch all .sls files (jerboa stdlib + vendor + project) to replace -;; the form with (void), matching what build-jcode-musl.ss does. Patches are -;; reverted at end of script via `git checkout`. - -(printf "==> [0.5/6] patching load-shared-object in libraries~n") -(define lso-patch-cmd - (string-append - "perl -i -0777 -pe 's/" - "\\(load-shared-object(?=\\s)" - "(?:[^()\"]++|\"(?:\\\\.|[^\"\\\\])*+\"|" - "(?<bal>\\((?:[^()\"]++|\"(?:\\\\.|[^\"\\\\])*+\"|(?&bal))*+\\))" - ")*+\\)/(void)/g'")) - -(define jerboa-lib-dir (format "~a/lib" jerboa-home)) -(system (format "find '~a' -name '*.sls' -exec ~a {} +" jerboa-lib-dir lso-patch-cmd)) -(system (format "find vendor/chez-sqlite -name '*.sls' -exec ~a {} +" lso-patch-cmd)) -(when (file-directory? "vendor/jerboa-websearch") - (system (format "find vendor/jerboa-websearch -name '*.sls' -exec ~a {} +" lso-patch-cmd))) -(when (file-directory? "lib") - (system (format "find lib -name '*.sls' -exec ~a {} +" lso-patch-cmd))) - -;; Delete stale .so files so they get recompiled with the patches. -(system (format "find '~a' -name '*.so' -delete 2>/dev/null" jerboa-lib-dir)) -(system "find vendor/chez-sqlite -name '*.so' -delete 2>/dev/null") -(system "find vendor/jerboa-websearch -name '*.so' -delete 2>/dev/null") -(system "find lib -name '*.so' -delete 2>/dev/null") - -(define (restore-patched-files!) - ;; Only restore .sls files — step 0.5 only patches .sls (never .ss), so a - ;; broad `git checkout -- .` would clobber unrelated .ss edits like vendor - ;; bug fixes that have to apply before compile-whole-program runs. - (printf "~n==> [cleanup] restoring patched .sls files via git~n") - (system (format "cd '~a' && git ls-files -z -- '*.sls' | xargs -0 git checkout -- 2>/dev/null" jerboa-home)) - (system "git ls-files -z -- 'lib/jcode/*.sls' | xargs -0 git checkout -- 2>/dev/null") - (system "cd vendor/chez-sqlite && git ls-files -z -- 'src/*.sls' | xargs -0 git checkout -- 2>/dev/null") - (when (file-directory? "vendor/jerboa-websearch") - (system "cd vendor/jerboa-websearch && git ls-files -z -- '*.sls' | xargs -0 git checkout -- 2>/dev/null"))) +;; ── Step 0.5: isolate cross-compiled objects ─────────────────────────────── +;; Never patch source libraries in-place. Chez xpatch can compile target +;; objects while `library-directories` maps source directories to a separate +;; writable object directory. + +(define obj-dir (format ".build/~a-obj" output)) +(define entry-so (format "~a/program.so" obj-dir)) +(define entry-wpo (format "~a/program.wpo" obj-dir)) + +(define (prepare-obj-dir!) + (system (format "rm -rf '~a'" obj-dir)) + (system (format "mkdir -p '~a'" obj-dir))) + +(define (cleanup!) + (system (format "rm -rf '~a'" obj-dir))) + +(prepare-obj-dir!) ;; ── Stage 1: load xpatch (target=ta6le emit mode) ────────────────────────── (define orig-libdirs (library-directories)) -(printf "==> [1/6] loading xpatch (compiler -> ta6le emit mode)~n") +(printf "==> [1/6] loading xpatch (compiler -> ta6fb emit mode)~n") (load xpatch) -(library-directories orig-libdirs) +(library-directories + (map (lambda (pair) + (cons (if (pair? pair) (car pair) pair) obj-dir)) + orig-libdirs)) (compile-imported-libraries #t) (generate-wpo-files #t) ;; ── Stage 2: compile-program main-binary.ss ──────────────────────────────── -(printf "==> [2/6] compile-program ~a~n" entry-script) -(guard (e [#t (restore-patched-files!) (raise e)]) - (compile-program entry-script)) +(printf "==> [2/6] compile-program ~a -> ~a~n" entry-script entry-so) +(guard (e [#t (cleanup!) (raise e)]) + (compile-program entry-script entry-so)) ;; ── Stage 3: compile-whole-program → wpo .so ─────────────────────────────── (define wpo-output (string-append output ".wp.so")) -(printf "==> [3/6] compile-whole-program main-binary.wpo -> ~a~n" wpo-output) -(guard (e [#t (restore-patched-files!) (raise e)]) - (compile-whole-program "main-binary.wpo" wpo-output #t)) +(printf "==> [3/6] compile-whole-program ~a -> ~a~n" entry-wpo wpo-output) +(guard (e [#t (cleanup!) (raise e)]) + (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) @@ -546,17 +527,11 @@ (printf " ~a~n" link-cmd) (let ([rc (system link-cmd)]) (unless (zero? rc) - (restore-patched-files!) + (cleanup!) (error 'build-jcode-freebsd-cross "cross-link failed" rc))) -;; ── Cleanup: restore patched files ────────────────────────────────────────── -(restore-patched-files!) - -;; Clean up intermediate compile-program outputs so the next dev cycle on -;; host scheme doesn't pick up ta6le-flavored .so files. -(for-each (lambda (f) - (when (file-exists? f) (delete-file f))) - '("main-binary.so" "main-binary.wpo")) +;; ── Cleanup: remove isolated cross objects ───────────────────────────────── +(cleanup!) (printf "~n=== Build complete: ~a ===~n" output) (system (format "ls -lh ~a" output)) --- a/build-jcode-musl.ss +++ b/build-jcode-musl.ss @@ -112,6 +112,17 @@ (printf "Jerboa lib: ~a~n" jerboa-dir) +(define build-dir "/tmp/jerboa-musl-jcode-build") +(define obj-dir (format "~a/obj" build-dir)) +(define program-so (format "~a/program.so" obj-dir)) + +(define (prepare-build-dir!) + (system (format "rm -rf '~a'" build-dir)) + (system (format "mkdir -p '~a'" obj-dir))) + +(define (cleanup-build-dir!) + (system (format "rm -rf '~a'" build-dir))) + ;; ========== Auto-discovery helpers ========== ;; ;; These helpers eliminate the hardcoded parallel lists of modules that @@ -277,52 +288,18 @@ ;; jerboa-native (net/io) — vectored I/O wrapper used by (std net io) "jerboa_writev2")) -;; ========== Step 0: Clean stale .so/.wpo files ========== - -(printf "[0/7] 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 -name '*.wpo' -delete 2>/dev/null" jerboa-dir)) - -;; ========== Step 0.5: Patch libraries for static linking ========== - -(printf "[0.5/7] Patching libraries for static linking...~n") - -;; Blanket-patch ALL .sls files to replace (load-shared-object ...) with (void). -;; In static builds, all FFI symbols are pre-registered via Sforeign_symbol — -;; load-shared-object is both unnecessary and unsupported. -;; This matches the approach used in jerboa-shell's musl build. -(printf " Blanket-patching load-shared-object in all libs...~n") -;; Paren-aware substitution. The naive sed `[^)]*` form breaks on: -;; 1. Nested forms: (load-shared-object (car candidates)) <- stops at first ) -;; 2. Multi-line forms in tui-ffi.sls -;; 3. The public helper (load-shared-object* name) in (jerboa ffi) -- this -;; MUST be preserved, since rewriting its body to (define (void) (void)) -;; causes "multiple definitions for void in body" failures. -;; The perl regex below uses a recursive named group to match balanced parens -;; and quoted strings, and (?=\s) to require whitespace after `object` so -;; `load-shared-object*` is left untouched. -(define lso-patch-cmd - (string-append - "perl -i -0777 -pe 's/" - "\\(load-shared-object(?=\\s)" - "(?:[^()\"]++|\"(?:\\\\.|[^\"\\\\])*+\"|" - "(?<bal>\\((?:[^()\"]++|\"(?:\\\\.|[^\"\\\\])*+\"|(?&bal))*+\\))" - ")*+\\)/(void)/g'")) - -(system (format "find '~a' -name '*.sls' -exec ~a {} +" jerboa-dir lso-patch-cmd)) -(system (format "find vendor/chez-sqlite -name '*.sls' -exec ~a {} +" lso-patch-cmd)) -(system (format "find lib -name '*.sls' -exec ~a {} +" lso-patch-cmd)) - -;; Delete ALL compiled .so in jerboa lib to force recompile with patches -(printf " Deleting stale .so files in all libs...~n") -(system (format "find '~a' -name '*.so' -delete 2>/dev/null" jerboa-dir)) -(system "find vendor/chez-sqlite -name '*.so' -delete 2>/dev/null") -(system "find lib -name '*.so' -delete 2>/dev/null") +;; ========== Step 0: Prepare isolated object output ========== + +(printf "[0/7] Preparing isolated build/object directories...~n") +(prepare-build-dir!) + +;; Compile imported libraries into obj-dir while loading sources from the +;; original --libdirs. This avoids modifying $JERBOA_HOME/lib, vendor/, or +;; generated lib/jcode files during static builds. +(library-directories + (map (lambda (pair) + (cons (if (pair? pair) (car pair) pair) obj-dir)) + (library-directories))) ;; ========== Step 1: Compile all modules ========== @@ -338,100 +315,56 @@ (enable-arithmetic-left-associative #t) (debug-level 0) (generate-inspector-information #f)) - (compile-program "main-binary.ss")) + (compile-program "main-binary.ss" program-so)) -;; Fail loud if compile-program didn't actually produce main-binary.so. +;; Fail loud if compile-program didn't actually produce the isolated program. ;; Historically this failure was silent — the script would continue until -;; step 5 died with a cryptic "open-file-input-port: failed for main-binary.so". -(unless (file-exists? "main-binary.so") - (printf "~n[ERROR] compile-program completed but main-binary.so was not produced.~n") +;; step 5 died with a cryptic open-file-input-port failure. +(unless (file-exists? program-so) + (printf "~n[ERROR] compile-program completed but program.so was not produced.~n") (printf " cwd: ~a~n" (current-directory)) (printf " entry: main-binary.ss~n") (printf " This usually means an import in main-binary.ss could not be resolved~n") - (printf " or a .sls file was corrupted by the blanket sed patching in step 0.5.~n") + (printf " or the isolated object directory was not writable: ~a~n" obj-dir) (error 'build-jcode-musl - "main-binary.so not produced by compile-program")) -(printf " → main-binary.so (~a bytes)~n" - (file-length (open-file-input-port "main-binary.so"))) + "program.so not produced by compile-program")) +(printf " → ~a (~a bytes)~n" + program-so + (file-length (open-file-input-port program-so))) ;; ========== Step 2: Skip WPO for musl builds ========== -;; Use the direct main-binary.so from compile-program. -(printf "[2/7] Skipping WPO (using main-binary.so directly)...~n") -(define program-so "main-binary.so") +;; Use the direct program.so from compile-program. +(printf "[2/7] Skipping WPO (using isolated program.so directly)...~n") -;; ========== Step 3: Auto-discover external libs ========== -;; -;; Historically this step held a hardcoded list of ~22 (std ...) modules to -;; pre-compile, and step 4 held a *second* parallel list of the same modules -;; to embed in the boot file. Both drifted every time jcode imported a new -;; stdlib module, and the failure mode was silent (missing entries were -;; quietly filtered out by `existing-so-files`). +;; ========== Step 3: Auto-discover compiled libraries ========== ;; -;; Instead: compile-program in step 1 already traversed main-binary.ss's full -;; import graph with compile-imported-libraries #t, emitting a .so next to -;; every imported .sls in $JERBOA_HOME/lib. Step 0.5 wiped that directory -;; clean beforehand, so every .so that now exists there is one the import -;; graph actually needs. Scan the directory to get the authoritative list. - -(printf "[3/7] Discovering external libs compiled under ~a...~n" jerboa-dir) - -;; Pick up jerboa stdlib .so files (~/mine/jerboa/lib) and any vendored -;; library sources that were compiled as part of main-binary.ss's import -;; graph. jerboa-websearch lives under vendor/ and is linked into jcode -;; through (jerbsearch ...) imports; its .so files won't show up under -;; jerboa-dir, so we scan vendor/ too. Without this, the static binary -;; tries to load (jerbsearch query) at runtime and dies with -;; "library (jerbsearch query) not found" because the import resolves -;; from --libdirs at start (and a static binary has none). -(define jerbsearch-vendor-dir "vendor/jerboa-websearch/src") - -(define external-lib-paths - (append - (find-files-with-suffix jerboa-dir ".so") - (if (file-directory? jerbsearch-vendor-dir) - (find-files-with-suffix jerbsearch-vendor-dir ".so") - '()))) - -(printf " Found ~a external lib .so file(s)~n" (length external-lib-paths)) -(when (null? external-lib-paths) +;; compile-program traversed main-binary.ss's import graph and wrote every +;; imported library object into obj-dir. Embed all of those library objects in +;; the boot image, excluding the entry program itself. + +(printf "[3/7] Discovering libraries compiled under ~a...~n" obj-dir) + +(define compiled-lib-paths + (filter (lambda (p) (not (string=? p program-so))) + (find-files-with-suffix obj-dir ".so"))) + +(printf " Found ~a compiled library .so file(s)~n" (length compiled-lib-paths)) +(when (null? compiled-lib-paths) (error 'build-jcode-musl - (format "No .so files under ~a after compile-program — did step 1 fail silently?" - jerboa-dir))) + (format "No library .so files under ~a after compile-program" obj-dir))) ;; ========== Step 4: Create libs-only boot file ========== (printf "[4/7] Creating libs-only boot file...~n") +(printf " Boot file contents: ~a compiled library .so files~n" + (length compiled-lib-paths)) -(define chez-sqlite-so "vendor/chez-sqlite/src/chez-sqlite.so") -(unless (file-exists? chez-sqlite-so) - (error 'build-jcode-musl - (format "chez-sqlite .so missing at ~a — was jerbuild run on vendor/?" chez-sqlite-so))) - -;; jcode module .so files live next to their .sls (same dir), so just swap -;; the suffix. Strict assertion surfaces any missing entry loudly. -(define jcode-so-files - (assert-so-files-exist! 'make-boot-file - (map (lambda (m) (format "~a.so" m)) jcode-modules) - "jcode module")) - -(printf " Boot file contents:~n") -(printf " ~a external lib .so files~n" (length external-lib-paths)) -(printf " 1 chez-sqlite shim .so~n") -(printf " ~a jcode module .so files~n" (length jcode-so-files)) - -(apply make-boot-file "jcode.boot" '("scheme" "petite") - (append - external-lib-paths - (list chez-sqlite-so) - jcode-so-files)) +(apply make-boot-file "jcode.boot" '("scheme" "petite") compiled-lib-paths) ;; ========== Step 5: Generate C with embedded boot files + program ========== (printf "[5/7] Generating C with embedded boot files + program...~n") -(define build-dir "/tmp/jerboa-musl-jcode-build") -(system (format "rm -rf '~a' && mkdir -p '~a'" build-dir build-dir)) - (define musl-lib-dir (musl-chez-lib-dir)) (define gcc (musl-gcc-path)) (define scheme-h-dir musl-lib-dir) @@ -766,28 +699,13 @@ (close-port port)) (printf " Wrote jcode-musl.sha256 (32 bytes)~n"))))) -;; ========== Restore patched files ========== - -(printf "~n[cleanup] Restoring patched files...~n") -;; Restore blanket-patched jerboa lib via git checkout -(system (format "cd '~a' && git checkout -- ." jerboa-dir-base)) -;; Restore patched local files -(system "git checkout -- lib/jcode/") -(system "cd vendor/chez-sqlite && git checkout -- src/chez-sqlite.sls") - -;; Cleanup build dir -(system (format "rm -rf '~a'" build-dir)) - -;; Clean up .so and .wpo from compile-imported-libraries -(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) +;; ========== Cleanup isolated build files ========== + +(printf "~n[cleanup] Removing isolated build directory...~n") +(cleanup-build-dir!) (for-each (lambda (f) (when (file-exists? f) (delete-file f))) - '("main-binary.so" "main-binary.wpo" "jcode.boot")) + '("jcode.boot")) ;; Summary (printf "~n========================================~n")