fix: extract shared build logic to prevent cross-platform drift
ober
8d00ff9f2572df6ccad59cf3782a40a32725cc2c
new file mode 100644 --- /dev/null +++ b/build-common.ss @@ -0,0 +1,168 @@ +;; build-common.ss — shared build logic for all gitsafe static binary builds. +;; +;; Include this file via (include "build-common.ss") AFTER defining: +;; jerboa-dir — absolute path to the Jerboa home directory +;; +;; Provides helpers, the gitsafe module list, and the six shared build steps: +;; setup-library-dirs! — Step 0: add jerboa lib to search path +;; do-compile! — Step 1: compile all modules with WPO +;; do-wpo! — Step 2: whole-program optimization (returns wpo-missing) +;; do-boot! — Step 3: make boot file + C headers +;; do-cleanup! — Step 6: remove intermediate files +;; +;; Steps 4 (generate C main) and 5 (compile + link) are platform-specific +;; and live in the including script. + +;; --- C byte-array header generation --- +(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))) + +;; --- Find the csv<version>/<machine-type> dir inside a Chez lib 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))) + +;; --- Filter a path list to files that actually exist --- +(define (existing-so-files paths) + (filter file-exists? paths)) + +;; --- Convert a library name to its .so path under jerboa-dir --- +;; e.g. (std misc string) → <jerboa-dir>/lib/std/misc/string.so +;; References `jerboa-dir` from the including script's scope. +(define (lib-name->so-path lib-name) + (let* ([parts (map symbol->string lib-name)] + [rel (let loop ([ps parts] [acc ""]) + (if (null? ps) + acc + (loop (cdr ps) + (if (string=? acc "") + (car ps) + (string-append acc "/" (car ps))))))] + [so (format "~a/lib/~a.so" jerboa-dir rel)]) + (and (file-exists? so) so))) + +;; --- gitsafe application modules (same on all platforms) --- +(define gitsafe-modules + '("gitsafe/entropy" + "gitsafe/config" + "gitsafe/allowlist" + "gitsafe/patterns" + "gitsafe/git" + "gitsafe/scanner" + "gitsafe/output")) + +;; --- Step 0: add library search paths --- +(define (setup-library-dirs!) + (library-directories + (append + (list (cons (current-directory) (current-directory)) + (cons (format "~a/lib" jerboa-dir) + (format "~a/lib" jerboa-dir))) + (library-directories)))) + +;; --- Step 1: compile all modules (optimize-level 3, WPO) --- +(define (do-compile!) + (printf "\n[1/6] Compiling all modules (optimize-level 3, WPO)...\n") + (parameterize ([compile-imported-libraries #t] + [optimize-level 3] + [cp0-effort-limit 500] + [cp0-score-limit 50] + [cp0-outer-unroll-limit 1] + [commonization-level 4] + [enable-unsafe-application #t] + [enable-unsafe-variable-reference #t] + [enable-arithmetic-left-associative #t] + [debug-level 0] + [generate-inspector-information #f] + [generate-wpo-files #t]) + (compile-program "gitsafe/main-binary.ss"))) + +;; --- Step 2: whole-program optimization --- +;; Returns the list of libraries not incorporated (no .wpo file available). +;; The caller passes this to do-boot! so they are bundled as .so files instead. +(define (do-wpo!) + (printf "[2/6] Running whole-program optimization...\n") + (let ([wpo-missing (compile-whole-program "gitsafe/main-binary.wpo" "gitsafe-all.so")]) + (unless (null? wpo-missing) + (printf " WPO: ~a libraries not incorporated (missing .wpo) — will bundle .so files:\n" + (length wpo-missing)) + (for-each (lambda (lib) (printf " ~a\n" lib)) wpo-missing)) + wpo-missing)) + +;; --- Step 3: create boot file and C headers --- +;; wpo-missing — list returned by do-wpo! +;; chez-boot-dir — directory containing petite.boot and scheme.boot +;; (the platform Chez install dir, NOT necessarily the host Chez) +(define (do-boot! wpo-missing chez-boot-dir) + (printf "[3/6] Creating boot file and C headers...\n") + ;; Find .so files for any stdlib lib that WPO couldn't inline. + (let ([missing-sos + (let loop ([libs wpo-missing] [acc '()]) + (if (null? libs) + (reverse acc) + (let ([so (lib-name->so-path (car libs))]) + (loop (cdr libs) (if so (cons so acc) acc)))))]) + (when (not (null? missing-sos)) + (printf " Bundling ~a stdlib .so files into boot image.\n" (length missing-sos))) + (apply make-boot-file "gitsafe.boot" '("scheme" "petite") + (existing-so-files + (append + (map (lambda (m) (format "~a.so" m)) gitsafe-modules) + missing-sos)))) + (file->c-header "gitsafe-all.so" + "gitsafe_program.h" + "gitsafe_program_data" "gitsafe_program_size") + (file->c-header (format "~a/petite.boot" chez-boot-dir) + "gitsafe_petite_boot.h" + "petite_boot_data" "petite_boot_size") + (file->c-header (format "~a/scheme.boot" chez-boot-dir) + "gitsafe_scheme_boot.h" + "scheme_boot_data" "scheme_boot_size") + (file->c-header "gitsafe.boot" + "gitsafe_boot.h" + "gitsafe_boot_data" "gitsafe_boot_size")) + +;; --- Step 6: remove intermediate files --- +;; platform: "macos" or "musl" — determines the C source/object file names +(define (do-cleanup! platform) + (printf "[6/6] Cleaning up intermediate files...\n") + (for-each (lambda (f) (when (file-exists? f) (delete-file f))) + (list (format "gitsafe-main-~a.c" platform) + (format "gitsafe-main-~a.o" platform) + "gitsafe_program.h" "gitsafe_petite_boot.h" + "gitsafe_scheme_boot.h" "gitsafe_boot.h" + "gitsafe-all.so" "gitsafe.boot" + "gitsafe/main-binary.wpo" "gitsafe/main-binary.so")) + (for-each (lambda (m) + (for-each (lambda (ext) + (let ([f (format "~a~a" m ext)]) + (when (file-exists? f) (delete-file f)))) + '(".so" ".wpo"))) + gitsafe-modules)) --- a/build-gitsafe-macos.sh +++ b/build-gitsafe-macos.sh @@ -84,6 +84,7 @@ if [ -f "gitsafe-macos" ]; then otool -L gitsafe-macos 2>/dev/null | tail -n +2 || true echo "" echo "Test: ./gitsafe-macos --version" + ./gitsafe-macos --version || { echo "ERROR: binary smoke test failed"; exit 1; } else echo "ERROR: gitsafe-macos not created" exit 1 --- a/build-gitsafe-macos.ss +++ b/build-gitsafe-macos.ss @@ -14,42 +14,12 @@ (import (chezscheme)) -;; --- Helper: generate C byte-array 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))) - -;; --- 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))) +;; Load shared build logic (defines find-csv-dir and all step functions). +;; jerboa-dir must be defined before any of the shared step functions are CALLED +;; (not before this include — lambdas capture it lazily). +(include "build-common.ss") +;; --- Locate Chez install directory (macOS) --- (define chez-dir (or (getenv "CHEZ_DIR") (let ([mt (symbol->string (machine-type))] @@ -63,7 +33,6 @@ (exit 1)) ;; --- Locate Jerboa --- -(define home (getenv "HOME")) (define jerboa-dir (or (getenv "JERBOA_HOME") (let ([sibling (format "~a/../jerboa" (current-directory))]) @@ -77,86 +46,13 @@ (printf "Jerboa dir: ~a\n" jerboa-dir) (printf "Machine type: ~a\n" (machine-type)) -;; Add library paths -(library-directories - (append - (list (cons (current-directory) (current-directory)) - (cons (format "~a/lib" jerboa-dir) - (format "~a/lib" jerboa-dir))) - (library-directories))) - -;; --- Step 1: Compile all modules (optimize-level 3, WPO) --- -(printf "\n[1/6] Compiling all modules (optimize-level 3, WPO)...\n") -(parameterize ([compile-imported-libraries #t] - [optimize-level 3] - [cp0-effort-limit 500] - [cp0-score-limit 50] - [cp0-outer-unroll-limit 1] - [commonization-level 4] - [enable-unsafe-application #t] - [enable-unsafe-variable-reference #t] - [enable-arithmetic-left-associative #t] - [debug-level 0] - [generate-inspector-information #f] - [generate-wpo-files #t]) - (compile-program "gitsafe/main-binary.ss")) - -;; --- Step 2: Whole-program optimization --- -(printf "[2/6] Running whole-program optimization...\n") -(let ([missing (compile-whole-program "gitsafe/main-binary.wpo" "gitsafe-all.so")]) - (unless (null? missing) - (printf " WPO: ~a libraries not incorporated (missing .wpo):\n" (length missing)) - (for-each (lambda (lib) (printf " ~a\n" lib)) missing))) - -;; --- Step 3: Create boot file + C headers --- -(printf "[3/6] Creating boot file and C headers...\n") - -(define (existing-so-files paths) - (filter file-exists? paths)) - -;; Standard library modules that WPO can't inline (no .wpo files). -;; These must be included in the boot file so the binary is self-contained. -;; Order matters: dependencies before dependents. -(define jerboa-std-modules - (map (lambda (m) (format "~a/lib/~a.so" jerboa-dir m)) - '("std/pregexp" - "std/os/path" - "std/text/json" - "std/misc/list" - "std/misc/process" - "std/misc/ports" - "std/misc/string" - "jerboa/runtime"))) +;; --- Steps 0–3: shared compile + WPO + boot file --- +(setup-library-dirs!) +(do-compile!) +(define wpo-missing (do-wpo!)) +(do-boot! wpo-missing chez-dir) -(define gitsafe-modules - '("gitsafe/entropy" - "gitsafe/config" - "gitsafe/allowlist" - "gitsafe/patterns" - "gitsafe/git" - "gitsafe/scanner" - "gitsafe/output")) - -(apply make-boot-file "gitsafe.boot" '("scheme" "petite") - (append - (existing-so-files jerboa-std-modules) - (existing-so-files - (map (lambda (m) (format "~a.so" m)) gitsafe-modules)))) - -(file->c-header "gitsafe-all.so" - "gitsafe_program.h" - "gitsafe_program_data" "gitsafe_program_size") -(file->c-header (format "~a/petite.boot" chez-dir) - "gitsafe_petite_boot.h" - "petite_boot_data" "petite_boot_size") -(file->c-header (format "~a/scheme.boot" chez-dir) - "gitsafe_scheme_boot.h" - "scheme_boot_data" "scheme_boot_size") -(file->c-header "gitsafe.boot" - "gitsafe_boot.h" - "gitsafe_boot_data" "gitsafe_boot_size") - -;; --- Step 4: Generate C main --- +;; --- Step 4: Generate C main (macOS — no dlopen stubs needed) --- (printf "[4/6] Generating C main...\n") (call-with-output-file "gitsafe-main-macos.c" @@ -197,15 +93,13 @@ (fprintf out "}\n")) 'replace) -;; --- Step 5: Compile and link (maximally static) --- +;; --- Step 5: Compile and link (maximally static, macOS) --- (printf "[5/6] Compiling and linking (maximally static)...\n") -;; Find static .a archives bundled with Chez (define kernel-a (format "~a/libkernel.a" chez-dir)) (define chez-lz4-a (format "~a/liblz4.a" chez-dir)) (define chez-z-a (format "~a/libz.a" chez-dir)) -;; Verify Chez static libs exist (for-each (lambda (pair) (unless (file-exists? (cdr pair)) @@ -215,7 +109,6 @@ (cons "liblz4.a" chez-lz4-a) (cons "libz.a" chez-z-a))) -;; Find ncurses static lib (from homebrew or env) (define ncurses-a (or (let ([p (getenv "NCURSES_STATIC_PATH")]) (and p (> (string-length p) 0) (file-exists? p) p)) @@ -230,7 +123,6 @@ (printf " zlib: ~a\n" chez-z-a) (printf " ncurses: ~a\n" (or ncurses-a "(dynamic fallback)")) -;; Build link command: static .a files + system dynamic libs (define static-libs (string-append kernel-a " " chez-lz4-a " " chez-z-a @@ -242,41 +134,21 @@ " -liconv -lpthread -lm")) (let ([cc (or (getenv "CC") "cc")]) - ;; Compile (let ([rc (system (format "~a -c -O2 -I~a -o gitsafe-main-macos.o gitsafe-main-macos.c" cc chez-dir))]) (unless (= rc 0) (printf "Error: C compilation failed\n") (exit 1))) - ;; Link: our main + static archives + system dylibs - ;; Note: Chez main.o is NOT included — it contains its own main() entry point. - ;; We provide our own main() that sets up embedded boot files. (let* ([cmd (format "~a -o gitsafe-macos gitsafe-main-macos.o ~a~a" cc static-libs dynamic-libs)]) (printf " Link: ~a\n" cmd) (let ([rc (system cmd)]) (unless (= rc 0) (printf "Error: linking failed\n") (exit 1))))) -;; Strip (printf " Stripping binary...\n") (system "strip -x gitsafe-macos") - -;; SHA256 (system "shasum -a 256 gitsafe-macos > gitsafe-macos.sha256") ;; --- Step 6: Cleanup --- -(printf "[6/6] Cleaning up intermediate files...\n") -(for-each (lambda (f) (when (file-exists? f) (delete-file f))) - '("gitsafe-main-macos.c" "gitsafe-main-macos.o" - "gitsafe_program.h" "gitsafe_petite_boot.h" - "gitsafe_scheme_boot.h" "gitsafe_boot.h" - "gitsafe-all.so" "gitsafe.boot" - "gitsafe/main-binary.wpo" "gitsafe/main-binary.so")) - -(for-each (lambda (m) - (for-each (lambda (ext) - (let ([f (format "~a~a" m ext)]) - (when (file-exists? f) (delete-file f)))) - '(".so" ".wpo"))) - gitsafe-modules) +(do-cleanup! "macos") (printf "\nDone! Binary: ./gitsafe-macos\n") (printf " Size: ") --- a/build-gitsafe-musl.sh +++ b/build-gitsafe-musl.sh @@ -60,6 +60,7 @@ if [ -f "gitsafe-musl" ]; then ldd gitsafe-musl 2>&1 || echo " (Fully static — no dynamic dependencies)" echo "" echo "Test: ./gitsafe-musl --version" + ./gitsafe-musl --version || { echo "ERROR: binary smoke test failed"; exit 1; } else echo "ERROR: gitsafe-musl not created" exit 1 --- a/build-gitsafe-musl.ss +++ b/build-gitsafe-musl.ss @@ -1,40 +1,23 @@ #!chezscheme ;; Build gitsafe as a fully static binary using musl libc. ;; -;; Usage: make gitsafe-musl-local +;; Usage: make linux-local ;; (runs via build-gitsafe-musl.sh → this script) ;; ;; Prerequisites: ;; - musl-gcc installed (apt install musl-tools) ;; - Chez Scheme built with: ./configure --threads --static CC=musl-gcc ;; installed to ~/chez-musl (or set JERBOA_MUSL_CHEZ_PREFIX) -;; - Stock scheme (glibc) for compilation steps +;; - Stock scheme (glibc) for the compilation steps ;; ;; Produces: ./gitsafe-musl (fully static ELF binary, zero runtime dependencies) (import (chezscheme)) -;; --- Helper: generate C byte-array 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))) +;; Load shared build logic (defines find-csv-dir and all step functions). +;; jerboa-dir must be defined before any of the shared step functions are CALLED +;; (not before this include — lambdas capture it lazily). +(include "build-common.ss") ;; --- Locate musl-built Chez Scheme --- (define musl-chez-prefix @@ -49,19 +32,6 @@ (display " See: https://github.com/ober/ChezScheme (build with --static CC=musl-gcc)\n") (exit 1)) -(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 musl-chez-dir (let ([mt (symbol->string (machine-type))]) (or (find-csv-dir (format "~a/lib" musl-chez-prefix) mt) @@ -73,7 +43,6 @@ (exit 1))))) ;; --- Locate Jerboa --- -(define home (getenv "HOME")) (define jerboa-dir (or (getenv "JERBOA_HOME") (let ([sibling (format "~a/../jerboa" (current-directory))]) @@ -87,71 +56,26 @@ (printf "Jerboa dir: ~a\n" jerboa-dir) (printf "Machine type: ~a\n" (machine-type)) -;; Add library paths (stock Chez for compilation) -(library-directories - (append - (list (cons (current-directory) (current-directory)) - (cons (format "~a/lib" jerboa-dir) - (format "~a/lib" jerboa-dir))) - (library-directories))) - -;; --- Step 1: Compile all modules (optimize-level 3, WPO) --- -(printf "\n[1/6] Compiling all modules (optimize-level 3, WPO)...\n") -(parameterize ([compile-imported-libraries #t] - [optimize-level 3] - [cp0-effort-limit 500] - [cp0-score-limit 50] - [cp0-outer-unroll-limit 1] - [commonization-level 4] - [enable-unsafe-application #t] - [enable-unsafe-variable-reference #t] - [enable-arithmetic-left-associative #t] - [debug-level 0] - [generate-inspector-information #f] - [generate-wpo-files #t]) - (compile-program "gitsafe/main-binary.ss")) - -;; --- Step 2: Whole-program optimization --- -(printf "[2/6] Running whole-program optimization...\n") -(let ([missing (compile-whole-program "gitsafe/main-binary.wpo" "gitsafe-all.so")]) - (unless (null? missing) - (printf " WPO: ~a libraries not incorporated (missing .wpo):\n" (length missing)) - (for-each (lambda (lib) (printf " ~a\n" lib)) missing))) - -;; --- Step 3: Create boot file + C headers --- -(printf "[3/6] Creating boot file and C headers...\n") - -(define (existing-so-files paths) - (filter file-exists? paths)) - -(define gitsafe-modules - '("gitsafe/entropy" - "gitsafe/config" - "gitsafe/allowlist" - "gitsafe/patterns" - "gitsafe/git" - "gitsafe/scanner" - "gitsafe/output")) +;; --- Steps 0–3: shared compile + WPO + boot file --- +;; Boot files come from the musl Chez (ABI must match the musl kernel). +(setup-library-dirs!) +(do-compile!) +(define wpo-missing (do-wpo!)) +(do-boot! wpo-missing musl-chez-dir) -(apply make-boot-file "gitsafe.boot" '("scheme" "petite") - (existing-so-files - (map (lambda (m) (format "~a.so" m)) gitsafe-modules))) - -;; Embed musl Chez boot files (must match musl kernel for ABI compatibility) -(file->c-header "gitsafe-all.so" - "gitsafe_program.h" - "gitsafe_program_data" "gitsafe_program_size") -(file->c-header (format "~a/petite.boot" musl-chez-dir) - "gitsafe_petite_boot.h" - "petite_boot_data" "petite_boot_size") -(file->c-header (format "~a/scheme.boot" musl-chez-dir) - "gitsafe_scheme_boot.h" - "scheme_boot_data" "scheme_boot_size") -(file->c-header "gitsafe.boot" - "gitsafe_boot.h" - "gitsafe_boot_data" "gitsafe_boot_size") - -;; --- Step 4: Generate C main with embedded program --- +;; --- Step 4: Generate C main (musl — with dlopen stubs + Sforeign_symbol) --- +;; +;; dlopen(NULL, ...) returns a fake self-handle so Chez can query its own +;; symbol table. All other dlopen calls return NULL, causing +;; (load-shared-object "libjerboa_native.so") in (std regex) to throw an +;; exception that the guard catches → native-available? = #f → all regex +;; falls back to the pure-Scheme pregexp engine. +;; +;; Sforeign_symbol MUST be called after Sbuild_heap (the foreign entry table +;; is not initialized until then). We register the three Rust regex symbols +;; with a harmless C stub so (std regex)'s (foreign-procedure ...) forms +;; succeed at WPO program init. The stub returns -1 but is never called +;; because native-available? = #f prevents all native regex code paths. (printf "[4/6] Generating C main...\n") (call-with-output-file "gitsafe-main-musl.c" @@ -168,18 +92,6 @@ (fprintf out "#include \"gitsafe_boot.h\"\n") (fprintf out "#include \"gitsafe_program.h\"\n") (fprintf out "\n") - ;; dlopen/dlsym stubs for fully static musl build. - ;; - ;; dlopen(NULL, ...) returns a fake self-handle so Chez can query its own - ;; symbol table. All other dlopen calls return NULL, causing - ;; (load-shared-object "libjerboa_native.so") in (std regex) to throw an - ;; exception that the guard catches → native-available? = #f → all regex - ;; falls back to the pure-Scheme pregexp engine. - ;; - ;; dlsym returns a harmless stub for the three known regex foreign-procedure - ;; symbols in case Chez resolves them eagerly on this build (empirically - ;; it can). The stub returns -1 but is never called because native-available? - ;; = #f prevents any code path that would invoke c-native-compile/find/free. (fprintf out "/* dlopen/dlsym stubs — fully static musl binary, no dynamic libraries */\n") (fprintf out "static int _jerboa_native_stub(void) { return -1; }\n") (fprintf out "void *dlopen(const char *f, int m) { (void)m; return (!f) ? (void*)1 : NULL; }\n") @@ -212,12 +124,6 @@ (fprintf out " Sregister_boot_file_bytes(\"scheme\", (void*)scheme_boot_data, scheme_boot_size);\n") (fprintf out " Sregister_boot_file_bytes(\"gitsafe\", (void*)gitsafe_boot_data, gitsafe_boot_size);\n") (fprintf out " Sbuild_heap(NULL, NULL);\n") - ;; Sforeign_symbol MUST be called after Sbuild_heap (foreign entry table is - ;; not initialized until then). We register the three Rust regex symbols with - ;; a harmless C stub so that (std regex)'s (foreign-procedure ...) definitions - ;; succeed when the WPO program initializes. The stub returns -1 but is never - ;; called: dlopen("libjerboa_native.so") returns NULL (our stub), so - ;; native-available? = #f, which prevents any call to c-native-compile/find/free. (fprintf out " /* Register regex native symbols AFTER Sbuild_heap */\n") (fprintf out " Sforeign_symbol(\"jerboa_regex_compile\", (void *)_jerboa_native_stub);\n") (fprintf out " Sforeign_symbol(\"jerboa_regex_find\", (void *)_jerboa_native_stub);\n") @@ -229,7 +135,7 @@ (fprintf out "}\n")) 'replace) -;; --- Step 5: Compile and link with musl-gcc --- +;; --- Step 5: Compile and link with musl-gcc (fully static) --- (printf "[5/6] Compiling and linking with musl-gcc (static)...\n") (define link-libs "-lkernel -llz4 -lz -lm -ldl -lpthread") @@ -242,26 +148,12 @@ musl-chez-dir link-libs))]) (unless (= rc 0) (printf "Error: linking failed\n") (exit 1))) -;; Strip and generate integrity hash (printf " Stripping binary...\n") (system "strip --strip-all gitsafe-musl") (system "sha256sum gitsafe-musl > gitsafe-musl.sha256") ;; --- Step 6: Cleanup --- -(printf "[6/6] Cleaning up intermediate files...\n") -(for-each (lambda (f) (when (file-exists? f) (delete-file f))) - '("gitsafe-main-musl.c" "gitsafe-main-musl.o" - "gitsafe_program.h" "gitsafe_petite_boot.h" - "gitsafe_scheme_boot.h" "gitsafe_boot.h" - "gitsafe-all.so" "gitsafe.boot" - "gitsafe/main-binary.wpo" "gitsafe/main-binary.so")) - -(for-each (lambda (m) - (for-each (lambda (ext) - (let ([f (format "~a~a" m ext)]) - (when (file-exists? f) (delete-file f)))) - '(".so" ".wpo"))) - gitsafe-modules) +(do-cleanup! "musl") (printf "\nDone! Binary: ./gitsafe-musl\n") (printf " Size: ")