Generate native-image binaries with sbt
This plugin makes it easy to generate native-image binaries with sbt. Key features:
- automatic GraalVM native-image installation powered by Coursier, no need to start sbt with a custom
$JAVA_HOMEor spin up Docker. See One-click install for Scala for more details.
- automatic support for Scala 2.12.12+ and 2.13.3+, no need to deal with issues like scala/bug#11634.
- works with Scala 3 (Dotty)
- get a notification when the binary is ready to use.
- works on macOS, Windows and Linux.
- works with Java 8 and Java 11.
- Getting started
- Generate native-image from GitHub Actions
- Comparison with sbt-native-packager
First, add the sbt plugin to your build in
// project/plugins.sbt addSbtPlugin("org.scalameta" % "sbt-native-image" % "0.2.2")
Next, enable the plugin to your native-image application in
build.sbt and configure the main class.
// build.sbt lazy val myNativeImageProject = project + .enablePlugins(NativeImagePlugin) .settings( // ... + Compile / mainClass := Some("com.my.MainClass") )
Finally, run the
nativeImage task to generate the binary.
$ sbt > myNativeImageProject/nativeImage ... [info] Native image ready! [info] /path/to/your/binary
nativeImageRun to execute the generated binary and manually test that it works as expected.
> myNativeImageProject/nativeImageRun argument1 argument 2 # output from your native-image binary
sbt-native-image provides several settings, tasks and input tasks to customize native-image generation and to automate your native-image workflows.
nativeImage: generate a native image
nativeImageOptions: customize native image generation
nativeImageRun: execute the generated native image
nativeImageCopy: generate a native image and copy the binary
nativeImageVersion: the GraalVM version to use for native-image
nativeImageJvm: the GraalVM JVM version to use for native-image
nativeImageJvmIndex: the index to use for resolving the JVM version
nativeImageCommand: the command to launch
nativeImageReady: callback hook when native-image is ready
nativeImageCoursier: the path to a
nativeImageOutput: the path to the generated native-image binary
Description: runs native-image and returns the resulting binary file.
Description: custom native-image linking options. See
native-image --help for available options. Empty by default.
nativeImageOptions ++= List("--initialize-at-build-time")
Description: executes the native-image binary with given arguments. This task can only be used after
nativeImage has completed.
sbt myProject/nativeImage 'myProject/nativeImageRun hello'
sbt clean myProject/nativeImageRun. Crashes because native-image does not exist.
Description: identical to
nativeImage except the resulting binary is additionally copied to the provided file. This task is helpful when configuring CI to generate the binary in a specific place.
sbt 'myProject/nativeImageCopy mybinary-x86_64-apple-darwin'.
sbt 'myProject/nativeImageCopy mybinary-x86_64-pc-linux'.
Description: the GraalVM version to use.
nativeImageVersion := "19.3.3"
Description: the GraalVM JVM version to use.
"graalvm-java11". Must be one of:
"graalvm" (Java 8).
nativeImageJvm := "graalvm"
Description: the index to use for resolving the JVM version. By default, uses the Cousier JVM index.
"cs". Must be one of:
nativeImageJvmIndex := "jabba".
Description: the base command that is used to launch native-image.
Default: automatically installs GraalVM
native-image via Coursier. Customize this setting if you prefer to manually install native-image.
nativeImageCommand := List("/path/to/native-image")
SettingKey[() => Unit]
Description: a side-effecting callback that is called the native image is ready.
Default: alerts the message "Native image ready!" via the
say command-line tool on macOS. Does nothing by default on Linux and Windows.
Description: the path to a
Default: copies a slim bootstrap binary from sbt-native-image resources. This setting is ignored if you customize
nativeImageCommand to use something else than Coursier.
Description: the path to the native-image binary that is generated.
NAME is the name of the sbt project. for available options.
nativeImageOutput := file("target") / "my-binary"
Generate native-image from GitHub Actions
The easiest way to distribute native-image binaries for Linux and macOS is to build the binaries in CI with GitHub Actions.
native.ymlfile from this repo into the
.github/workflows/directory in your project.
mkdir -p .github/workflows && \ curl -L https://raw.githubusercontent.com/scalameta/sbt-native-image/master/.github/workflows/native.yml > .github/workflows/native.yml
Edit the file to replace "example" with the name of your binary.
Commit your changes.
Push your commit to GitHub and see the binary get uploaded as an artifact to the CI job.
Create a GitHub release and see the binary get uploaded as assets to the release page.
Comparison with sbt-native-packager
The sbt-native-packager plugin provides similar support to generate native-image binaries. Check out their documentation at https://sbt-native-packager.readthedocs.io/en/stable/formats/graalvm-native-image.html
The key differences between sbt-native-packager and sbt-native-image are:
- sbt-native-image automatically installs GraalVM native-image by default. You don't need to configure a docker image or manually install a correct GraalVM JDK before starting sbt.
- sbt-native-image automatically works out-of-the-box with Scala 2.12.12+ and 2.13.3+. You don't need custom settings to work around issues like like scala/bug#11634.
- sbt-native-image displays live progress output from the
native-imagewhile it's generating the binary. For some reason, sbt-native-packager only displays output from native-image after the process completes (see issue #1345).
- sbt-native-packager has Docker support, which is helpful if you need more fine-grained control over the linking environment. There are no plans to add Docker support in sbt-native-image.