graalvm 2025-09-28

I want to embed a git commit hash in my binary. I added (def COMMIT (ps/shell "git describe --always")) to my clojure file, which works fine when running as a script. But when I compile to graal, I get this error:

Fatal error: com.oracle.graal.pointsto.constraints.UnsupportedFeatureException: Detected a started Thread in the image heap. Thread name: clojure-agent-send-off-pool-0. Threads running in the image generator are no longer running at image runtime. If these objects should not be stored in the image heap, you can use
Is there a way to tell Clojure to shutdown any threads that are running after the module is initialized? or the opposite, to tell ps/shell to spawn processes from the main thread instead of trying not to block?

including (shutdown-agents) at the end should work

ohhh at the module level instead of in main-

yes that makes sense

hmm no that wouldn't work, then you can't run any futures or agents in -main anymore

ah yeah i see that 😅

flower join-frontmatter: error: java.util.concurrent.RejectedExecutionException: Task java.util.concurrent.FutureTask@383496a0[Not completed, task = clojure.core$binding_conveyor_fn$fn__5844@41f9b699] rejected from java.util.concurrent.ThreadPoolExecutor@2142b70d[Terminated, pool size = 0, active threads = 0, queued tasks = 0, completed tasks = 1]

is there some equivalent startup-agents i could call in main?

I do something similar in babashka but via an env var. I do this:

BABASHKA_COMMIT_SHA=... native-image -EBABASHKA_COMMIT_SHA
and
(def COMMIT (System/getenv "BABASHKA_COMMIT_SHA"))

-EBABASHKA_COMMIT_SHA means that this env var is supposed to be captured at build time

ah hm, i could probably do this in my build.clj

let me mess around with dynamic bindings

why dynamic bindings?

because i want this to work for uberjars, not just for graal executables

i'm not sure java has any equivalent of setenv but if it did i guess that would work

for uberjars I wouldn't use env vars, I would just spit the commit sha to a file and include it in the resources

You could also spit out a little clojure namespace with a single def among the sha as part of the build process

oh i don't like that lol

i would rather do that resource thing

my build process is complicated enough as is

> for uberjars I wouldn't use env vars, I would just spit the commit sha to a file and include it in the resources this worked quite well, ty 🙂

actually this is even better than "run git at startup" because now i'm able to still test the output in snapshot tests

👍 1

My two cents: it will be simpler just to add a resource file called VERSION with a version line. Then, you have a function get-version that slurps that resource.

which is basically what she settled on, but note that the version in her case has to be a compile time constant which you can accomplish by doing the expression at the top level

So you have this as a part of your Makefile:

get describe --bla > VERSION
and then in your native image args:
-H:IncludeResources='^VERSION$$'
and in Clojure:
(defn get-version []
 (-> "VERSION" io/resource slurp))

that's also possible yes

note that it helps to qualify your version file to not get conflicts with other projects that include their version on the classpath

yeah, worth naming it like MY_PROJECT_VERSION . It could be also be MY_PROJECT_META with version, author, etc

done that as well: https://github.com/nextjournal/clerk/blob/main/resources/META-INF/nextjournal/clerk/meta.edn it seems I've had about every variation of this in one project or another ;)

😆 1

> note that it helps to qualify your version file to not get conflicts with other projects that include their version on the classpath i've been putting all my resources in META-INF/resources/flower

unclear if this is actually the intended directory, but it's nice and unambiguous, so

I think that's a good location 👍

🙂 1