jolt build: compile an app to a standalone binary (Phase 4 stages 1-2)
Restores the standalone-binary capability the Janet host had. `bin/joltc build -m NS -o OUT` AOT-compiles an app into a single self-contained executable — the whole runtime, clojure.core, stdlib and compiler embedded, no Chez install or jolt source needed at runtime. Pipeline (host/chez/build.ss, host primitive jolt.host/build-binary driven by jolt.main's build command): resolve deps, load the entry namespace recording the app namespaces in dependency order, re-emit each to Scheme, textually inline the cli.ss runtime load sequence into one flat source + the app + a launcher, then compile-file -> make-boot-file -> embed the boot as C bytes -> cc-link against libkernel.a. Two non-obvious bits: the compile pass runs in a fresh Chez, not the loaded runtime (regex.ss shadows top-level `error`, which otherwise bakes a broken reference into the boot); and the launcher installs scheme-start rather than running -main at top level, since boot top-level forms execute during heap build before argv is set, so args only reach -main through scheme-start. Loader: a require of an in-memory namespace with no source file now no-ops, so AOT'd app namespaces satisfy require in a built binary. Mode flags (--opt/--dev, default release) are plumbed; the optimization passes they gate come in a later stage. RFC 0007 has the design. Gated by `make buildsmoke`.
This commit is contained in:
parent
33eff7c7d8
commit
43778eafd7
10 changed files with 554 additions and 12 deletions
|
|
@ -112,6 +112,28 @@
|
|||
(map? task) (do (apply-project! resolved) (apply-main-opts (:main-opts task) more))
|
||||
:else (throw (ex-info (str "bad task " name) {})))))
|
||||
|
||||
;; build [-m NS | FILE] [-o OUT] [--opt | --dev] — AOT-compile the app into a
|
||||
;; standalone executable. Resolves deps + roots like `run`, then hands the entry
|
||||
;; namespace to the host build driver (jolt.host/build-binary, defined by
|
||||
;; build.ss). Default mode is release; --opt selects optimized, --dev unoptimized.
|
||||
(defn- cmd-build [more]
|
||||
(apply-project! (deps/resolve-project (project-dir)))
|
||||
(let [opts (loop [a more, entry nil, out nil]
|
||||
(cond
|
||||
(empty? a) {:entry entry :out out}
|
||||
(= "-m" (first a)) (recur (drop 2 a) (second a) out)
|
||||
(= "-o" (first a)) (recur (drop 2 a) entry (second a))
|
||||
(str/starts-with? (first a) "-") (recur (rest a) entry out)
|
||||
:else (recur (rest a) (or entry (first a)) out)))
|
||||
entry (:entry opts)
|
||||
mode (cond (some #{"--opt"} more) "optimized"
|
||||
(some #{"--dev"} more) "dev"
|
||||
:else "release")]
|
||||
(when (nil? entry)
|
||||
(throw (ex-info "build needs an entry: -m NS" {})))
|
||||
(let [out (or (:out opts) (first (str/split entry #"\.")))]
|
||||
(jolt.host/build-binary entry out mode))))
|
||||
|
||||
(defn- nrepl [more]
|
||||
;; resolve the project (deps on the roots, native libs loaded), then start the
|
||||
;; nREPL server so an editor can connect and (require '[some.lib]) live. A
|
||||
|
|
@ -128,6 +150,7 @@
|
|||
(println "usage: jolt <command> [args]")
|
||||
(println " run -m NS [args] resolve deps.edn, load NS, call its -main")
|
||||
(println " run FILE load a Clojure file")
|
||||
(println " build -m NS [-o OUT] [--opt|--dev] compile a standalone binary")
|
||||
(println " -M:alias [args] run the alias's :main-opts")
|
||||
(println " -A:alias [args] add the alias's paths/deps")
|
||||
(println " repl start a line REPL")
|
||||
|
|
@ -146,4 +169,5 @@
|
|||
(str/starts-with? cmd "-M") (cmd-M cmd more)
|
||||
(str/starts-with? cmd "-A") (cmd-A cmd more)
|
||||
(= cmd "-m") (cmd-run (cons "-m" more))
|
||||
(= cmd "build") (cmd-build more)
|
||||
:else (run-task cmd more))))
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue