From c8167e1c05afd39554f1ac506ce2c6b444eabe63 Mon Sep 17 00:00:00 2001 From: Yogthos Date: Sat, 4 Jul 2026 16:40:14 -0400 Subject: [PATCH] JOLT_TRACE: honor the env at runtime in a built joltc MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The JOLT_TRACE opt-in was a top-level form in compile-eval.ss, so in a self-contained joltc it ran at heap-build time — where JOLT_TRACE is always unset — and never at runtime. `JOLT_TRACE=1 joltc -M:run` therefore produced no trace from the distributed binary (it worked only under the source-loaded dev launcher). REPL/nREPL tracing was unaffected (those enable at runtime). Make it a jolt-trace-init-from-env! fn called from the runtime entrypoints — the cli.ss dispatch and the built-joltc launcher — before any app namespace compiles, so the app's own code is traced. While here, drop a redundant trace print in the joltc launcher (jolt-report-throwable already emits it) that double-printed the block once tracing actually produced one. joltc-selfbuild-smoke asserts JOLT_TRACE=1 through the built binary yields exactly one tail-frame trace. --- host/chez/build-joltc.ss | 9 ++++----- host/chez/cli.ss | 3 +++ host/chez/compile-eval.ss | 15 ++++++++++----- host/chez/joltc-selfbuild-smoke.sh | 14 ++++++++++++++ 4 files changed, 31 insertions(+), 10 deletions(-) diff --git a/host/chez/build-joltc.ss b/host/chez/build-joltc.ss index d6d1132..12612a1 100644 --- a/host/chez/build-joltc.ss +++ b/host/chez/build-joltc.ss @@ -145,11 +145,10 @@ (scheme-start (lambda args (set-source-roots! (list \"jolt-core\" \"stdlib\")) - (guard (v (#t (jolt-report-throwable v (current-error-port)) - (let ((bt (jolt-backtrace-string v))) - (when bt (display \" trace:\\n\" (current-error-port)) - (display bt (current-error-port)))) - (exit 1))) + ;; JOLT_TRACE at RUNTIME (the env is unset at heap-build), before any app ns + ;; compiles, so a `-M:run` traces the app's own code. + (jolt-trace-init-from-env!) + (guard (v (#t (jolt-report-throwable v (current-error-port)) (exit 1))) (cond ((and (= (length args) 2) (string=? (car args) \"-e\")) (let ((result (jolt-final-str diff --git a/host/chez/cli.ss b/host/chez/cli.ss index 9e580c1..7d978af 100644 --- a/host/chez/cli.ss +++ b/host/chez/cli.ss @@ -66,6 +66,9 @@ (when bt (display " trace:\n" port) (display bt port))) (exit 1))) +;; JOLT_TRACE opt-in, at runtime (before any app ns compiles) so the app is traced. +(jolt-trace-init-from-env!) + (guard (v (#t (jolt-report-uncaught v))) (cond ;; -e EXPR — evaluate one expression and print it (blank for nil). Wrapped in diff --git a/host/chez/compile-eval.ss b/host/chez/compile-eval.ss index 52dffc0..4c2da62 100644 --- a/host/chez/compile-eval.ss +++ b/host/chez/compile-eval.ss @@ -132,11 +132,16 @@ ;; push is baked in at compile time, only code compiled after this call is traced — ;; which is exactly the code you eval / reload in a live session. (def-var! "jolt.host" "enable-trace!" jolt-enable-trace!) -;; Explicit opt-in for a whole run (JOLT_TRACE=1): enable at load, BEFORE any app -;; namespace is compiled, so a plain `-M:run` traces the app's own code too. Only an -;; affirmative value (set, non-empty, not falsey) forces it on here. -(let ((e (getenv "JOLT_TRACE"))) - (when (and e (fx>? (string-length e) 0) (not (jolt-trace-env-off? e))) (jolt-enable-trace!))) +;; Explicit opt-in for a whole run (JOLT_TRACE=1): turn tracing on BEFORE any app +;; namespace is compiled, so a plain `-M:run` traces the app's own code too. Called +;; from the runtime entrypoints (cli.ss, and the built joltc launcher) — NOT at load +;; time: a built joltc runs top-level forms at heap-build time, where JOLT_TRACE is +;; always unset, so a load-time check would never see the user's runtime env. Only an +;; affirmative value (set, non-empty, not falsey) forces it on. +(define (jolt-trace-init-from-env!) + (let ((e (getenv "JOLT_TRACE"))) + (when (and e (fx>? (string-length e) 0) (not (jolt-trace-env-off? e))) + (jolt-enable-trace!)))) ;; (with-meta sym m) -> sym, else x — an (ns ^:no-doc name …) yields the name with ;; reader metadata as a with-meta form; strip it to read the bare ns symbol. diff --git a/host/chez/joltc-selfbuild-smoke.sh b/host/chez/joltc-selfbuild-smoke.sh index 5fae720..b9f267a 100644 --- a/host/chez/joltc-selfbuild-smoke.sh +++ b/host/chez/joltc-selfbuild-smoke.sh @@ -42,6 +42,20 @@ if [ "$got_e" != "45" ]; then exit 1 fi +# 2b. JOLT_TRACE must take effect in the BUILT binary. The env check runs at +# runtime (the launcher), NOT at heap-build where JOLT_TRACE is always unset — so +# an uncaught error shows a tail-frame trace recovering the TCO-elided chain, and +# exactly ONE trace block (the launcher must not double-print it). +got_tr="$(env -i HOME="$HOME" JOLT_TRACE=1 "$joltc" -e '(defn a [x] (+ x 1)) (defn b [x] (a x)) (b :x)' 2>&1)" +if ! printf '%s' "$got_tr" | grep -q ' trace:' || ! printf '%s' "$got_tr" | grep -q 'b'; then + echo " FAIL: JOLT_TRACE=1 in the built joltc produced no tail-frame trace" + echo "--- got ---"; echo "$got_tr"; exit 1 +fi +if [ "$(printf '%s' "$got_tr" | grep -c ' trace:')" != "1" ]; then + echo " FAIL: built joltc double-printed the trace block" + echo "--- got ---"; echo "$got_tr"; exit 1 +fi + # 3. Build an app through the distributed joltc with an EMPTY environment — no # PATH at all, so no chez, no cc, no shell tools are reachable. This is the core # guarantee: joltc compiles apps entirely on its own.