A Leiningen plugin to build GraalVM native images
A Leiningen plugin for generating GraalVM native images from your project.
The
lein native-imagecommand compiles your project then uses GraalVM's
native-imageto build a native image.
For deps.edn projects, try clj.native-image.
NOTE: As of GraalVM 19.0.0,
native-imageis 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-imageexecutable will be in thebindirectory, 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)
:mainnamespace w/entrypoint and support AOT compilation:
clojure :main ^:skip-aot my-app.core
See the examples directory for projects that can be compiled to native images with GraalVM:
Configure your project with a custom image name, path to GraalVM's home directory or
native-imagepath, or
native-imageCLI options: ```clojure (defproject my-app "0.1.0" :plugins [[io.taylorwood/lein-native-image "0.3.1"]] ;; or in ~/.lein/profiles.clj
:native-image {:name "my-app" ;; name of output image, optional :graal-bin "/path/to/graalvm/" ;; path to GraalVM home, optional :opts ["--verbose"]} ;; pass-thru args to GraalVM native-image, optional
;; optionally set profile-specific :native-image overrides :profiles {:test ;; e.g. lein with-profile +test native-image {:native-image {:opts ["--report-unsupported-elements-at-runtime" "--initialize-at-build-time" "--verbose"]}}
:uberjar ;; used by default {:aot :all :native-image {:jvm-opts ["-Dclojure.compiler.direct-linking=true"]}}})
`:native-image` config keys:
:nameis an optional name for the generated native image.
:graal-binpath can be specified as a string or resolved from an environment variable using a keyword e.g.
:env/GRAALVM_HOME. If
:graal-binis unspecified, the
GRAALVM_HOMEenvironment variable will be used by default.
:optsis an optional vector of arguments to
native-image; see its documentation for more.
Note: task-specific
:native-imageprofile will be merged in by default, or the
:uberjarprofile if that doesn't exist.
You can also specify these in your Leiningen user profile
~/.lein/profiles.clj:
clojure {:user {:plugins [[io.taylorwood/lein-native-image "0.3.1"]] :native-image {:graal-bin "/path/to/graalvm-ce-19.0.0/Contents/Home/bin"}}}
Build a native image from your project:
➜ lein native-image Compiling my-app.core Build on Server(pid: 36212, port: 26681) classlist: 332.89 ms (cap): 1,289.90 ms 8
Execute the native image:
➜ ./target/my-app with optional args Hello, World!
The primary benefits to using a GraalVM native image are faster startup, lower memory requirements, and smaller distribution footprint (no JDK/JRE required). This doesn't necessarily mean the same code will run faster than it would on the JVM. GraalVM Community Edition and Enterprise Edition also have different performance characteristics.
GraalVM's native image capabilities have evolved across many release candidates. Several AOT issues have been fixed since 1.0.0-RC1. GraalVM and Substrate VM's support for AOT compilation and native images has limitations, and there are unsupported features. This release and its example projects were tested with GraalVM 19.0.0 Community Edition.
GraalVM 19.0.0 (first non-RC release) changes the default class-initialization behavior of
native-image. Now you must specify
--initialize-at-build-timeexplicitly in your
native-imageoptions.
There is a known issue where usages of
clojure.core/lockingmacro will fail compilation. Clojure 1.10 depends on a version of clojure.spec that uses
locking. See this commit for an example workaround.
When the
--report-unsupported-elements-at-runtimeflag is set, some
native-imageAOT compilation issues will be deferred as runtime exceptions. You can try specifying this flag if
native-imagecompilation fails. To avoid unexpected errors at runtime, don't use this flag for "production" builds.
Set
--enable-url-protocols=httpto use HTTP libraries. HTTPS is available as of 1.0.0-RC7 (e.g.
--enable-url-protocols=http,https) but requires additional configuration.
Specifying
:jvm-opts ["-Dclojure.compiler.direct-linking=true"]might allow for better compile-time optimizations.
This plugin doesn't shutdown GraalVM
native-imagebuild servers after builds, so that subsequent builds are slightly faster. You can set
:opts ["--no-server"]to not spawn a build server at all, or use GraalVM's
native-imagecommand directly to manage build server(s).
GraalVM Native Image AOT Compilation
Instant Netty Startup using GraalVM (and source)
You'll need Leiningen and GraalVM installed to build and test the plugin.
Issues and PRs are welcome!
Copyright © 2019 Taylor Wood.
Distributed under the MIT License.