Liking cljdoc? Tell your friends :D

com.blockether.vis.internal.nativeimage

GraalVM native-image build-time Feature: initialize Clojure namespaces the right way so build-time class initialization doesn't blow up.

The problem: graal-build-time registers every Clojure-generated package for build-time class initialization. native-image then runs each <clinit> RAW on a parallel analysis worker thread, with no Clojure thread-binding frame. Any namespace whose body has a top-level (set! *warn-on-reflection* true) (most libraries — babashka.fs, next.jdbc, rewrite-clj, honeysql, nippy, …) throws

java.lang.IllegalStateException: Can't change/establish root binding of:
*warn-on-reflection* with set

because set! on a dynamic var requires a thread binding. Core namespaces (clojure.string, clojure.spec.alpha, …) survive only because clojure.core's bootstrap loads them through require, which DOES push that binding. Libraries reached directly by the analysis get no such courtesy.

The fix: in beforeAnalysis — which runs in the image-builder JVM, before the analysis can raw-init anything — require every app + extension namespace with the compiler vars bound. require initializes each class through Clojure's loader (binding active), so its set! succeeds; by the time the analysis marks the class build-time-initialized it is already initialized and is not re-run.

Wired via --features=com.blockether.vis.internal.nativeimage in main's resources/META-INF/native-image/com.blockether/vis/native-image.properties, alongside graal-build-time's feature. Build-time only — never loaded at runtime.

GraalVM native-image build-time Feature: initialize Clojure namespaces the
*right* way so build-time class initialization doesn't blow up.

The problem: `graal-build-time` registers every Clojure-generated package for
build-time class initialization. native-image then runs each `<clinit>` RAW on
a parallel analysis worker thread, with no Clojure thread-binding frame. Any
namespace whose body has a top-level `(set! *warn-on-reflection* true)` (most
libraries — babashka.fs, next.jdbc, rewrite-clj, honeysql, nippy, …) throws

    java.lang.IllegalStateException: Can't change/establish root binding of:
    *warn-on-reflection* with set

because `set!` on a dynamic var requires a thread binding. Core namespaces
(clojure.string, clojure.spec.alpha, …) survive only because clojure.core's
bootstrap loads them through `require`, which DOES push that binding. Libraries
reached directly by the analysis get no such courtesy.

The fix: in `beforeAnalysis` — which runs in the image-builder JVM, before the
analysis can raw-init anything — `require` every app + extension namespace with
the compiler vars bound. `require` initializes each class through Clojure's
loader (binding active), so its `set!` succeeds; by the time the analysis marks
the class build-time-initialized it is already initialized and is not re-run.

Wired via `--features=com.blockether.vis.internal.nativeimage` in main's
`resources/META-INF/native-image/com.blockether/vis/native-image.properties`,
alongside graal-build-time's feature. Build-time only — never loaded at runtime.
raw docstring

-afterAnalysisclj

(-afterAnalysis _ _)
source

-afterCompilationclj

(-afterCompilation _ _)
source

-afterHeapLayoutclj

(-afterHeapLayout _ _)
source

-afterImageWriteclj

(-afterImageWrite _ _)
source

-afterRegistrationclj

(-afterRegistration _ _)
source

-beforeAnalysisclj

(-beforeAnalysis _ _)
source

-beforeCompilationclj

(-beforeCompilation _ _)
source

-beforeHeapLayoutclj

(-beforeHeapLayout _ _)
source

-beforeImageWriteclj

(-beforeImageWrite _ _)
source

-beforeUniverseBuildingclj

(-beforeUniverseBuilding _ _)
source

-cleanupclj

(-cleanup _)
source

-duringAnalysisclj

(-duringAnalysis _ _)
source

-duringSetupclj

(-duringSetup _ _)
source

-getDescriptionclj

(-getDescription _)
source

-getRequiredFeaturesclj

(-getRequiredFeatures _)
source

-getURLclj

(-getURL _)
source

-isInConfigurationclj

(-isInConfiguration _ _)
source

-onAnalysisExitclj

(-onAnalysisExit _ _)
source

-onRegistrationclj

(-onRegistration _ _)
source

cljdoc builds & hosts documentation for Clojure/Script libraries

Keyboard shortcuts
Ctrl+kJump to recent docs
Move to previous article
Move to next article
Ctrl+/Jump to the search field
× close