Build GraalVM native images using Clojure Deps and CLI tools.
This should be useful for creating lightweight, native CLI executables using Clojure and deps.edn
.
See clj.native-cli for a starter project template.
This project depends on tools.deps.alpha and should be considered alpha itself.
-
NOTE: As of GraalVM 19.0.0,
native-image
is no longer included by default:Native Image was extracted from the base GraalVM distribution. Currently it is available as an early adopter plugin. To install it, run:
gu install native-image
. After this additional step, thenative-image
executable will be in thebin
directory, as for the previous releases.➜ $GRAALVM_HOME/bin/gu install native-image Downloading: Component catalog from www.graalvm.org Processing component archive: Native Image Downloading: Component native-image: Native Image from github.com Installing new component: Native Image licence files (org.graalvm.native-image, version 19.0.0)
Assuming a project structure like this:
.
├── deps.edn
└── src
└── core.clj
In your deps.edn
specify an alias with a dependency on clj.native-image
:
{:aliases {:native-image
{:main-opts ["-m" "clj.native-image" "core"
"--initialize-at-build-time"
;; optional native image name override
"-H:Name=core"]
:jvm-opts ["-Dclojure.compiler.direct-linking=true"]
:extra-deps
{clj.native-image/clj.native-image
{:git/url "https://github.com/taylorwood/clj.native-image.git"
:sha "7708e7fd4572459c81f6a6b8e44c96f41cdd92d4"}}}}}
Where core.clj
is a class with -main
entrypoint, for example:
(ns core
(:gen-class))
(defn -main [& args]
(println "Hello, World!"))
From your project directory, invoke clojure
with the native-image
alias, specifying the main namespace
(core
in example above):
➜ clojure -A:native-image
Loading core
Compiling core
Building native image 'core' with classpath 'classes:src:etc.'
classlist: 1,944.26 ms
8<----------------------
[total]: 38,970.37 ms
Note: Either GRAALVM_HOME
environment variable must be set, or GraalVM's native-image
path must be passed as an argument,
and any additional arguments
will be passed to native-image
e.g.:
➜ clojure -A:native-image --verbose
You can now execute the native image:
➜ ./core
Hello, World!
See this Gist for another example.
There are example deps.edn projects in the lein-native-image repo:
- jdnsmith - CLI JSON-to-EDN transformer
- http-api - simple HTTP API server
- clojurl - cURL-like tool using clojure.spec, HTTPS, hiccup
The --no-server
flag is passed to native-image
by default, to avoid creating orphaned build servers.
Also see caveats section of lein-native-image.
GraalVM Native Image AOT Compilation
This project was inspired by depstar.
You'll need Clojure CLI tooling and GraalVM installed to test locally.
Just change the source of the clj.native-image
dependency to a :local/root
instead of :git/url
.
Issues, PRs, and suggestions are welcome!
Copyright © 2018 Taylor Wood.
Distributed under the MIT License.