jerbuild binary: --rust-target + --csv-dir for cross-builds
ober
fb74ab1e840da579f27433228e634e82e6f3cd01
--- a/jerbuild.ss +++ b/jerbuild.ss @@ -1427,6 +1427,24 @@ acc)] [else (loop (cdr args) cc (cons (car args) acc))]))) +(define (parse-single-flag args flag-name) + ;; Scan for FLAG <value> (or FLAG=<value>). Returns (values value remaining). + ;; Last occurrence wins. Returns #f if absent. + (let* ([eq-prefix (string-append flag-name "=")] + [eq-len (string-length eq-prefix)]) + (let loop ([args args] [value #f] [acc '()]) + (cond + [(null? args) (values value (reverse acc))] + [(string=? (car args) flag-name) + (when (null? (cdr args)) + (error 'jerbuild (format "~a requires a value" flag-name))) + (loop (cddr args) (cadr args) acc)] + [(string-starts-with? (car args) eq-prefix) + (loop (cdr args) + (substring (car args) eq-len (string-length (car args))) + acc)] + [else (loop (cdr args) value (cons (car args) acc))])))) + (define (shell-quote s) ;; Wrap s in single quotes, escaping any embedded single quote. (let* ([len (string-length s)] @@ -1645,9 +1663,11 @@ int main(int argc, const char *argv[]) { (directory-list dir)))) '())) -(define (build-rust-crate spec) +(define (build-rust-crate spec rust-target) ;; spec: "path/Cargo.toml[:features]" - ;; Drives `cargo build --release [--features F]`; returns list of .a paths. + ;; rust-target: triple string (e.g., "aarch64-unknown-linux-musl") or #f + ;; Drives `cargo build --release [--features F] [--target T]`; returns + ;; list of .a paths under target/[<triple>/]release/. (let-values ([(cargo-toml features) (parse-rust-crate-spec spec)]) (unless (file-exists? cargo-toml) (error 'jerbuild (format "rust-crate: Cargo.toml not found: ~a" cargo-toml))) @@ -1655,15 +1675,20 @@ int main(int argc, const char *argv[]) { [features-arg (if features (format " --features ~a" (shell-quote features)) "")] - [cmd (format "cargo build --release --manifest-path ~a~a" - (shell-quote cargo-toml) features-arg)]) + [target-arg (if rust-target + (format " --target ~a" (shell-quote rust-target)) + "")] + [cmd (format "cargo build --release --manifest-path ~a~a~a" + (shell-quote cargo-toml) features-arg target-arg)]) (printf " ~a\n" cmd) (let ([rc (system cmd)]) (unless (zero? rc) (error 'jerbuild (format "rust-crate: cargo build failed (rc=~a) for ~a" rc cargo-toml)))) - (let* ([release-dir (format "~a/target/release" manifest-dir)] + (let* ([release-dir (if rust-target + (format "~a/target/~a/release" manifest-dir rust-target) + (format "~a/target/release" manifest-dir))] [archives (list-archives-in release-dir)]) (when (null? archives) (error 'jerbuild @@ -1709,6 +1734,8 @@ int main(int argc, const char *argv[]) { ;; [--extra-ldflag F] (repeatable) ;; [--rust-crate Cargo.toml[:features]] (repeatable) ;; [--main-c FILE] (single) + ;; [--rust-target TRIPLE] (single) + ;; [--csv-dir PATH] (single) ;; <entry.ss> <output> ;; ;; Builds a standalone executable that bundles Chez + the user's entry script @@ -1720,31 +1747,41 @@ int main(int argc, const char *argv[]) { (let-values ([(extra-sources args) (parse-multi-flag args "--extra-source")]) (let-values ([(extra-ldflags args) (parse-multi-flag args "--extra-ldflag")]) (let-values ([(rust-crates args) (parse-multi-flag args "--rust-crate")]) - (let-values ([(main-cs rest) (parse-multi-flag args "--main-c")]) - (let ([main-c-override - (cond - [(null? main-cs) #f] - [else (car (reverse main-cs))])] - ;; Wrap each extra-source path as (path . #f) — no - ;; per-source cflags supported on the CLI; use .jerbuild - ;; for that. - [extra-sources-pairs - (map (lambda (s) (cons s #f)) extra-sources)]) - (do-binary-build libs cc-arg extra-archives - extra-sources-pairs - extra-ldflags rust-crates main-c-override - ;; CLI form: no ffi-symbols, pre-build, or - ;; pre-link — those are config-only. - #f '() '() (current-directory) - rest)))))))))) + (let-values ([(main-cs args) (parse-multi-flag args "--main-c")]) + (let-values ([(rust-target args) (parse-single-flag args "--rust-target")]) + (let-values ([(csv-dir rest) (parse-single-flag args "--csv-dir")]) + (let ([main-c-override + (cond + [(null? main-cs) #f] + [else (car (reverse main-cs))])] + ;; Wrap each extra-source path as (path . #f) — no + ;; per-source cflags supported on the CLI; use .jerbuild + ;; for that. + [extra-sources-pairs + (map (lambda (s) (cons s #f)) extra-sources)]) + (do-binary-build libs cc-arg extra-archives + extra-sources-pairs + extra-ldflags rust-crates main-c-override + ;; CLI form: no ffi-symbols, pre-build, or + ;; pre-link — those are config-only. + #f '() '() + rust-target csv-dir + (current-directory) + rest)))))))))))) (define (do-binary-build libs cc-arg extra-archives extra-sources extra-ldflags rust-crates main-c-override - ffi-symbols pre-build pre-link config-dir rest) + ffi-symbols pre-build pre-link + rust-target csv-dir-override + config-dir rest) ;; extra-sources is a list of pairs (abs-path . cflags-or-#f). + ;; rust-target: triple passed to `cargo build --target=` or #f for host. + ;; csv-dir-override: full path to a csv-dir (containing petite.boot, + ;; scheme.boot, libkernel.a, scheme.h). When set, replaces the default + ;; bundle path. Lets cross-builds point at a Chez built for the target. (when (< (length rest) 2) (error 'jerbuild - "binary: usage: jerbuild binary [--libdirs P] [--cc CC] [--extra-archive A] [--extra-source S.c] [--extra-ldflag F] [--rust-crate Cargo.toml[:features]] <entry.ss> <output>")) + "binary: usage: jerbuild binary [--libdirs P] [--cc CC] [--extra-archive A] [--extra-source S.c] [--extra-ldflag F] [--rust-crate Cargo.toml[:features]] [--rust-target T] [--csv-dir D] [--main-c F] <entry.ss> <output>")) (let* ([entry (car rest)] [output (cadr rest)] [cc (or cc-arg (or (getenv "CC") "cc"))] @@ -1752,7 +1789,7 @@ int main(int argc, const char *argv[]) { (error 'jerbuild "binary: JERBUILD_BUNDLE_DIR not set (jerbuild internal bug)"))] [mt (machine-type)] - [csv-dir (format "~a/csv/~a" bundle-dir mt)] + [csv-dir (or csv-dir-override (format "~a/csv/~a" bundle-dir mt))] [petite-boot (format "~a/petite.boot" csv-dir)] [scheme-boot (format "~a/scheme.boot" csv-dir)] [libkernel (format "~a/libkernel.a" csv-dir)] @@ -1813,7 +1850,10 @@ int main(int argc, const char *argv[]) { (printf " Output: ~a\n" output) (printf " Host: ~a\n" mt) (printf " CC: ~a\n" cc) - (printf " Chez: ~a\n" csv-dir) + (printf " Chez: ~a~a\n" csv-dir + (if csv-dir-override " (override)" "")) + (when rust-target + (printf " Rust target: ~a\n" rust-target)) (unless (null? rust-crates) (printf " Rust crates: ~a\n" (length rust-crates))) (unless (null? extra-archives) @@ -1850,7 +1890,9 @@ int main(int argc, const char *argv[]) { [(null? rust-crates) '()] [else (printf "==> [2/5] Build Rust crates (~a)\n" (length rust-crates)) - (apply append (map build-rust-crate rust-crates))])] + (apply append + (map (lambda (spec) (build-rust-crate spec rust-target)) + rust-crates))])] [user-objs (cond [(null? extra-sources) '()] @@ -1976,6 +2018,20 @@ int main(int argc, const char *argv[]) { ;; (pre-link "rust-dedup.sh") ; optional; sh commands run AFTER C ;; ; compile but BEFORE final link. ;; ; Env: JERBUILD_OBJ_DIR, JERBUILD_OUTPUT +;; (rust-target "aarch64-unknown-linux-musl") ; optional; cross target. +;; ; Passed to `cargo build --target=…` +;; ; and switches the archive search to +;; ; target/<triple>/release/. +;; ; CLI --rust-target overrides. +;; (csv-dir "vendor/chez/aarch64-linux/csv/tarm64le") ; optional override of +;; ; the Chez csv-dir (default: bundle +;; ; csv for the host machine-type). Use +;; ; for cross-builds — point at csv/ +;; ; files (petite.boot, scheme.boot, +;; ; libkernel.a, scheme.h, optionally +;; ; liblz4.a/libz.a) built for the +;; ; target machine. CLI --csv-dir +;; ; overrides. ;; ;; All paths are resolved relative to the .jerbuild file's directory. @@ -2041,7 +2097,9 @@ int main(int argc, const char *argv[]) { (define (load-jerbuild-config path) ;; Returns (values entry output libdirs cc rust-crates ;; extra-sources extra-archives extra-ldflags main-c - ;; ffi-symbols pre-build pre-link). + ;; ffi-symbols pre-build pre-link + ;; rust-target csv-dir + ;; config-dir). ;; extra-sources entries are pairs (abs-path . cflags-or-#f). (let* ([config-dir (path-dirname path)] [base (if (absolute-path? config-dir) @@ -2051,7 +2109,8 @@ int main(int argc, const char *argv[]) { [entry #f] [output #f] [cc #f] [main-c #f] [ffi-symbols #f] [libdirs '()] [rust-crates '()] [extra-sources '()] [extra-archives '()] [extra-ldflags '()] - [pre-build '()] [pre-link '()]) + [pre-build '()] [pre-link '()] + [rust-target #f] [csv-dir #f]) (for-each (lambda (form) (unless (and (pair? form) (symbol? (car form))) @@ -2096,9 +2155,17 @@ int main(int argc, const char *argv[]) { (set! pre-build (append pre-build (cdr form)))] [(pre-link) (set! pre-link (append pre-link (cdr form)))] + [(rust-target) + (unless (= (length form) 2) + (error 'jerbuild "config: (rust-target TRIPLE) takes one value")) + (set! rust-target (cadr form))] + [(csv-dir) + (unless (= (length form) 2) + (error 'jerbuild "config: (csv-dir PATH) takes one value")) + (set! csv-dir (resolve-config-path (cadr form) base))] [else (error 'jerbuild - (format "config: unknown key ~a in ~a (valid: entry output cc libdirs rust-crates extra-sources extra-archives extra-ldflags main-c ffi-symbols pre-build pre-link)" + (format "config: unknown key ~a in ~a (valid: entry output cc libdirs rust-crates extra-sources extra-archives extra-ldflags main-c ffi-symbols pre-build pre-link rust-target csv-dir)" (car form) path))])) forms) (unless entry @@ -2107,40 +2174,50 @@ int main(int argc, const char *argv[]) { (error 'jerbuild (format "config: missing required (output PATH) in ~a" path))) (values entry output libdirs cc rust-crates extra-sources extra-archives extra-ldflags main-c - ffi-symbols pre-build pre-link base))) + ffi-symbols pre-build pre-link + rust-target csv-dir + base))) (define (run-build args) ;; jerbuild build [--cc CC] [--config PATH] + ;; [--rust-target TRIPLE] [--csv-dir PATH] ;; Reads .jerbuild from cwd (or any parent) and runs do-binary-build. - ;; --cc overrides the config's (cc ...) setting. + ;; --cc / --rust-target / --csv-dir override the config's settings. (let-values ([(cc-arg rest1) (parse-cc-flag args)]) - (let-values ([(config-paths rest) (parse-multi-flag rest1 "--config")]) - (unless (null? rest) - (error 'jerbuild - (format "build: unexpected positional args ~a" rest))) - (let ([config-path - (cond - [(not (null? config-paths)) - (let ([p (car (reverse config-paths))]) - (unless (file-exists? p) - (error 'jerbuild (format "build: --config not found: ~a" p))) - p)] - [else - (or (find-config-from (current-directory)) - (error 'jerbuild - "build: no .jerbuild found in cwd or any parent"))])]) - (printf "=== jerbuild build ===\n") - (printf " Config: ~a\n" config-path) - (let-values ([(entry output libdirs cfg-cc rust-crates - extra-sources extra-archives extra-ldflags main-c - ffi-symbols pre-build pre-link config-dir) - (load-jerbuild-config config-path)]) - (do-binary-build libdirs - (or cc-arg cfg-cc) - extra-archives extra-sources extra-ldflags - rust-crates main-c - ffi-symbols pre-build pre-link config-dir - (list entry output))))))) + (let-values ([(config-paths rest2) (parse-multi-flag rest1 "--config")]) + (let-values ([(rt-arg rest3) (parse-single-flag rest2 "--rust-target")]) + (let-values ([(csv-arg rest) (parse-single-flag rest3 "--csv-dir")]) + (unless (null? rest) + (error 'jerbuild + (format "build: unexpected positional args ~a" rest))) + (let ([config-path + (cond + [(not (null? config-paths)) + (let ([p (car (reverse config-paths))]) + (unless (file-exists? p) + (error 'jerbuild (format "build: --config not found: ~a" p))) + p)] + [else + (or (find-config-from (current-directory)) + (error 'jerbuild + "build: no .jerbuild found in cwd or any parent"))])]) + (printf "=== jerbuild build ===\n") + (printf " Config: ~a\n" config-path) + (let-values ([(entry output libdirs cfg-cc rust-crates + extra-sources extra-archives extra-ldflags main-c + ffi-symbols pre-build pre-link + cfg-rust-target cfg-csv-dir + config-dir) + (load-jerbuild-config config-path)]) + (do-binary-build libdirs + (or cc-arg cfg-cc) + extra-archives extra-sources extra-ldflags + rust-crates main-c + ffi-symbols pre-build pre-link + (or rt-arg cfg-rust-target) + (or csv-arg cfg-csv-dir) + config-dir + (list entry output))))))))) ;;;; ============================================================ ;;;; Entry point --- a/support/build-jerbuild.sh +++ b/support/build-jerbuild.sh @@ -352,9 +352,10 @@ int main(int argc, const char *argv[]) { " jerbuild binary [--libdirs <p>] [--cc CC]\n" " [--extra-archive A] [--extra-source S.c]\n" " [--extra-ldflag F] [--rust-crate Cargo.toml[:features]]\n" - " [--main-c FILE]\n" + " [--main-c FILE] [--rust-target T] [--csv-dir D]\n" " <entry.ss> <output> # build standalone binary\n" - " jerbuild build [--cc CC] [--config PATH] # read .jerbuild, build\n" + " jerbuild build [--cc CC] [--config PATH]\n" + " [--rust-target T] [--csv-dir D] # read .jerbuild, build\n" " jerbuild --jerboa-home # extract+print stdlib path\n" " jerbuild --version\n", stdout);