build: a no-main entry namespace runs as a script instead of crashing
jolt build -m ns on a namespace with only top-level side effects and no
-main produced a binary that printed its output, then crashed calling a nil
-main ("nil cannot be cast to IFn"). The launcher now calls -main only when
the entry ns actually defines one; otherwise the top-level forms (already run
at heap build) are the whole program and it exits cleanly. Regression case
added to build-smoke.sh.
This commit is contained in:
parent
403c3f302f
commit
dbc5afac32
2 changed files with 25 additions and 3 deletions
|
|
@ -129,4 +129,20 @@ if [ "$got_dr" != "42" ]; then
|
|||
echo " FAIL: built #code data reader — want 42, got \`$got_dr\`"; exit 1
|
||||
fi
|
||||
|
||||
echo "build smoke: passed (release + optimized + direct-link + tree-shake + compiler+core shake + data-reader)"
|
||||
# A script namespace with no -main (just top-level side effects) must build and
|
||||
# run its top-level forms, then exit cleanly — not crash calling a nil -main.
|
||||
nomain="$(dirname "$out")/nomain"
|
||||
mkdir -p "$nomain/src"
|
||||
printf '{:paths ["src"]}\n' > "$nomain/deps.edn"
|
||||
printf '(ns script)\n(println "no-main script ran")\n' > "$nomain/src/script.clj"
|
||||
nmout="$(dirname "$out")/nomain-bin"
|
||||
if ! JOLT_PWD="$nomain" bin/joltc build -m script -o "$nmout" >/dev/null 2>&1; then
|
||||
echo " FAIL: jolt build of a no-main script exited non-zero"; exit 1
|
||||
fi
|
||||
got_nm="$(cd / && "$nmout" 2>&1)"; rc_nm=$?
|
||||
if [ "$got_nm" != "no-main script ran" ] || [ "$rc_nm" != "0" ]; then
|
||||
echo " FAIL: no-main script binary — want 'no-main script ran' rc 0, got \`$got_nm\` rc $rc_nm"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
echo "build smoke: passed (release + optimized + direct-link + tree-shake + compiler+core shake + data-reader + no-main)"
|
||||
|
|
|
|||
|
|
@ -571,11 +571,17 @@
|
|||
"))\n"
|
||||
" (list \"jolt-core\" \"stdlib\"))))\n"))
|
||||
(put-string out (string-append
|
||||
" (let ((mainv (var-deref " (ei-str-lit entry-ns) " \"-main\")))\n"
|
||||
;; Call -main only if the entry namespace defines one;
|
||||
;; a script ns (top-level side effects, no -main) has
|
||||
;; already run its forms at heap build, so invoking a nil
|
||||
;; -main would crash ("nil cannot be cast to IFn") — just
|
||||
;; exit cleanly instead.
|
||||
" (let ((maincell (var-cell-lookup " (ei-str-lit entry-ns) " \"-main\")))\n"
|
||||
;; render an uncaught throw (+ Clojure backtrace) instead
|
||||
;; of Chez's opaque dump, then exit non-zero.
|
||||
" (guard (v (#t (jolt-report-throwable v (current-error-port)) (exit 1)))\n"
|
||||
" (apply jolt-invoke mainv args)))\n"
|
||||
" (when (and maincell (var-cell-defined? maincell))\n"
|
||||
" (apply jolt-invoke (var-cell-root maincell) args))))\n"
|
||||
" (exit 0)))\n"))
|
||||
(close-port out))
|
||||
;; 4. compile -> boot -> link. Two paths, chosen by whether this process
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue