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_HOME
or 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.
- get a notification when the binary is ready to use.
- works on macOS, Windows and Linux.
- works with Java 8 and Java 11.
Overview:
- Getting started
- Configuration
- Generate native-image from GitHub Actions
- Comparison with sbt-native-packager
Getting started
First, add the sbt plugin to your build in project/plugins.sbt
.
// project/plugins.sbt
addSbtPlugin("org.scalameta" % "sbt-native-image" % "0.2.1")
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
Optionally, use 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
Configuration
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 imagenativeImageOptions
: customize native image generationnativeImageRun
: execute the generated native imagenativeImageCopy
: generate a native image and copy the binarynativeImageVersion
: the GraalVM version to use for native-imagenativeImageJvm
: the GraalVM JVM version to use for native-imagenativeImageCommand
: the command to launchnative-image
nativeImageReady
: callback hook when native-image is readynativeImageCoursier
: the path to acoursier
binarynativeImageOutput
: the path to the generated native-image binary
nativeImage
Type: TaskKey[File]
Description: runs native-image and returns the resulting binary file.
Example usage: sbt myProject/nativeImage
nativeImageOptions
Type: TaskKey[Seq[String]]
Description: custom native-image linking options. See native-image --help
for available options. Empty by default.
Example usage: nativeImageOptions ++= List("--initialize-at-build-time")
nativeImageRun
Type: InputKey[File]
Description: executes the native-image binary with given arguments. This
task can only be used after nativeImage
has completed.
Example usage:
sbt myProject/nativeImage 'myProject/nativeImageRun hello'
- Error:
sbt clean myProject/nativeImageRun
. Crashes because native-image does not exist.
nativeImageCopy
Type: InputKey[File]
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.
Example usage:
sbt 'myProject/nativeImageCopy mybinary-x86_64-apple-darwin'
.sbt 'myProject/nativeImageCopy mybinary-x86_64-pc-linux'
.
nativeImageVersion
Type: SettingKey[String]
Description: the GraalVM version to use.
Default: 20.1.0
Example usage: nativeImageVersion := "19.3.3"
nativeImageJvm
Type: SettingKey[String]
Description: the GraalVM JVM version to use.
Default: "graalvm-java11"
. Must be one of: "graalvm-java11"
, "graalvm"
(Java 8).
Example usage: nativeImageJvm := "graalvm"
nativeImageCommand
Type: TaskKey[Seq[String]]
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.
Example usage: nativeImageCommand := List("/path/to/native-image")
nativeImageReady
Type: 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.
nativeImageCoursier
Type: TaskKey[File]
Description: the path to a coursier
binary.
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.
nativeImageOutput
Type: SettingKey[File]
Description: the path to the native-image binary that is generated.
Default: target/native-image/NAME
where NAME
is the name of the sbt
project. for available options.
Example usage: 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.
-
Copy the
native.yml
file 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-image
while 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.