This plugin makes it easy to generate native-image binaries with sbt. Key features:
$JAVA_HOME or spin up Docker. See
One-click install for Scala
for more details.Overview:
First, add the sbt plugin to your build in project/plugins.sbt.
// project/plugins.sbt
addSbtPlugin("org.scalameta" % "sbt-native-image" % "0.4.0")
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")
)
Additionally, if your app uses reflection or JNI, you may need to run nativeImageRunAgent command to capture runtime information. For more details, see nativeImageRunAgent section.
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
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-imagenativeImageJvmIndex: the index to use for resolving
the JVM versionnativeImageCommand: the command to launch
native-imagenativeImageReady: callback hook when native-image is
readynativeImageCoursier: the path to a coursier binarynativeImageOutput: the path to the generated
native-image binarynativeImageInstalled: whether GraalVM is manually
installed or should be downloaded with coursiernativeImageGraalHome: path to GraalVM home
directorynativeImageRunAgent: run application, tracking all
usages of dynamic features of an execution with
native-image-agentnativeImageAgentOutputDir: directory where
native-image-agent should put generated configurationsnativeImageAgentMerge: whether
native-image-agent should merge generated configurationsnativeImageType: TaskKey[File]
Description: runs native-image and returns the resulting binary file.
Example usage: sbt myProject/nativeImage
nativeImageOptionsType: 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")
nativeImageRunType: 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'sbt clean myProject/nativeImageRun. Crashes because native-image does
not exist.nativeImageCopyType: 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'.nativeImageVersionType: SettingKey[String]
Description: the GraalVM version to use.
Default: 20.2.0
Example usage: nativeImageVersion := "19.3.3"
nativeImageJvmType: SettingKey[String]
Description: the GraalVM JVM version to use.
Default: "graalvm-java11". Must be one of the combinations below.
Example usage: nativeImageJvm := "graalvm"
| nativeImageJvm | nativeImageVersion | nativeImageJvmIndex | source |
|---|---|---|---|
| graalvm, graalvm-java11, graalvm-java17 | 1.0.0-x,19.0.0~21.1.0 | cs | https://github.com/coursier/jvm-index |
| graalvm-ce-java8, graalvm-ce-java11, graalvm-ce-java16 | 19.3~21.1.0 | jabba | https://raw.githubusercontent.com/shyiko/jabba/master/index.json |
nativeImageJvmIndexType: SettingKey[String]
Description: the index to use for resolving the JVM version. By default, uses the Cousier JVM index.
Default: "cs". Must be one of: "cs", "jabba".
Example usage: nativeImageJvmIndex := "jabba".
nativeImageCommandType: TaskKey[Seq[String]]
Description: the base command that is used to launch native-image.
Default: resolves the command using nativeImageGraalHome task.
Example usage: nativeImageCommand := List("/path/to/native-image")
nativeImageReadyType: 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.
nativeImageCoursierType: 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.
nativeImageOutputType: 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"
nativeImageInstalledType: SettingKey[Boolean]
Description: whether GraalVM is manually installed or should be downloaded with coursier.
Default: checks if NATIVE_IMAGE_INSTALLED / GRAALVM_INSTALLED
environment variables or native-image-installed / graalvm-installed
properties are set to true.
nativeImageGraalHomeType: TaskKey[Path]
Description: path to GraalVM home directory.
Default: if nativeImageInstalled is true, then tries to read the path
from environment variables 1) GRAAL_HOME, 2) GRAALVM_HOME or 3) JAVA_HOME
(in given order). Otherwise, automatically installs GraalVM via
Coursier. Customize this setting if you prefer to
not to use environment variables.
Example usage:
nativeImageGraalHome := file("/path/to/graalvm/base/directory").toPath
nativeImageRunAgentType: InputKey[Unit]
Description: run application, tracking all usages of dynamic features of an
execution with
native-image-agent.
You may need to run this command if your app or any dependency uses reflection or JNI.
Example usage:
First, add the reflection configuration to the native image options
// build.sbt
lazy val myNativeProject = project
.settings(
+ nativeImageOptions += s"-H:ReflectionConfigurationFiles=${target.value / "native-image-configs" / "reflect-config.json"}",
+ nativeImageOptions += s"-H:ConfigurationFileDirectories=${target.value / "native-image-configs" }",
+ nativeImageOptions +="-H:+JNI"
)
.enablePlugins(NativeImagePlugin)
Then, make sure to generate the reflection configuration with
nativeImageRunAgent before running nativeImage.
# Step 0: Start sbt shell.
$ sbt
# Step 1: Run application on the JVM with native-image agent.
> myProject/nativeImageRunAgent arg1 arg2
# Step 2: Create native-image binary with assisted configuration.
> myProject/nativeImage
# Step 3: Run native-image that was generated with assisted configuration.
> myProject/nativeImageRun arg1 arg2
nativeImageAgentOutputDirType: SettingKey[File]
Description: directory where native-image-agent should put generated
configurations.
Default: baseDirectory.value / "native-image-configs"
Example usage:
nativeImageAgentOutputDir := baseDirectory.value / "native-image-agent" / "out"
nativeImageAgentMergeType: SettingKey[Boolean]
Description: whether native-image-agent should merge generated
configurations.
Default: false
Example usage: nativeImageAgentMerge := true
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.
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:
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).Scala
93.9%
Batchfile
6.1%
This plugin makes it easy to generate native-image binaries with sbt. Key features:
$JAVA_HOME or spin up Docker. See
One-click install for Scala
for more details.Overview:
First, add the sbt plugin to your build in project/plugins.sbt.
// project/plugins.sbt
addSbtPlugin("org.scalameta" % "sbt-native-image" % "0.4.0")
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")
)
Additionally, if your app uses reflection or JNI, you may need to run nativeImageRunAgent command to capture runtime information. For more details, see nativeImageRunAgent section.
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
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-imagenativeImageJvmIndex: the index to use for resolving
the JVM versionnativeImageCommand: the command to launch
native-imagenativeImageReady: callback hook when native-image is
readynativeImageCoursier: the path to a coursier binarynativeImageOutput: the path to the generated
native-image binarynativeImageInstalled: whether GraalVM is manually
installed or should be downloaded with coursiernativeImageGraalHome: path to GraalVM home
directorynativeImageRunAgent: run application, tracking all
usages of dynamic features of an execution with
native-image-agentnativeImageAgentOutputDir: directory where
native-image-agent should put generated configurationsnativeImageAgentMerge: whether
native-image-agent should merge generated configurationsnativeImageType: TaskKey[File]
Description: runs native-image and returns the resulting binary file.
Example usage: sbt myProject/nativeImage
nativeImageOptionsType: 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")
nativeImageRunType: 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'sbt clean myProject/nativeImageRun. Crashes because native-image does
not exist.nativeImageCopyType: 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'.nativeImageVersionType: SettingKey[String]
Description: the GraalVM version to use.
Default: 20.2.0
Example usage: nativeImageVersion := "19.3.3"
nativeImageJvmType: SettingKey[String]
Description: the GraalVM JVM version to use.
Default: "graalvm-java11". Must be one of the combinations below.
Example usage: nativeImageJvm := "graalvm"
| nativeImageJvm | nativeImageVersion | nativeImageJvmIndex | source |
|---|---|---|---|
| graalvm, graalvm-java11, graalvm-java17 | 1.0.0-x,19.0.0~21.1.0 | cs | https://github.com/coursier/jvm-index |
| graalvm-ce-java8, graalvm-ce-java11, graalvm-ce-java16 | 19.3~21.1.0 | jabba | https://raw.githubusercontent.com/shyiko/jabba/master/index.json |
nativeImageJvmIndexType: SettingKey[String]
Description: the index to use for resolving the JVM version. By default, uses the Cousier JVM index.
Default: "cs". Must be one of: "cs", "jabba".
Example usage: nativeImageJvmIndex := "jabba".
nativeImageCommandType: TaskKey[Seq[String]]
Description: the base command that is used to launch native-image.
Default: resolves the command using nativeImageGraalHome task.
Example usage: nativeImageCommand := List("/path/to/native-image")
nativeImageReadyType: 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.
nativeImageCoursierType: 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.
nativeImageOutputType: 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"
nativeImageInstalledType: SettingKey[Boolean]
Description: whether GraalVM is manually installed or should be downloaded with coursier.
Default: checks if NATIVE_IMAGE_INSTALLED / GRAALVM_INSTALLED
environment variables or native-image-installed / graalvm-installed
properties are set to true.
nativeImageGraalHomeType: TaskKey[Path]
Description: path to GraalVM home directory.
Default: if nativeImageInstalled is true, then tries to read the path
from environment variables 1) GRAAL_HOME, 2) GRAALVM_HOME or 3) JAVA_HOME
(in given order). Otherwise, automatically installs GraalVM via
Coursier. Customize this setting if you prefer to
not to use environment variables.
Example usage:
nativeImageGraalHome := file("/path/to/graalvm/base/directory").toPath
nativeImageRunAgentType: InputKey[Unit]
Description: run application, tracking all usages of dynamic features of an
execution with
native-image-agent.
You may need to run this command if your app or any dependency uses reflection or JNI.
Example usage:
First, add the reflection configuration to the native image options
// build.sbt
lazy val myNativeProject = project
.settings(
+ nativeImageOptions += s"-H:ReflectionConfigurationFiles=${target.value / "native-image-configs" / "reflect-config.json"}",
+ nativeImageOptions += s"-H:ConfigurationFileDirectories=${target.value / "native-image-configs" }",
+ nativeImageOptions +="-H:+JNI"
)
.enablePlugins(NativeImagePlugin)
Then, make sure to generate the reflection configuration with
nativeImageRunAgent before running nativeImage.
# Step 0: Start sbt shell.
$ sbt
# Step 1: Run application on the JVM with native-image agent.
> myProject/nativeImageRunAgent arg1 arg2
# Step 2: Create native-image binary with assisted configuration.
> myProject/nativeImage
# Step 3: Run native-image that was generated with assisted configuration.
> myProject/nativeImageRun arg1 arg2
nativeImageAgentOutputDirType: SettingKey[File]
Description: directory where native-image-agent should put generated
configurations.
Default: baseDirectory.value / "native-image-configs"
Example usage:
nativeImageAgentOutputDir := baseDirectory.value / "native-image-agent" / "out"
nativeImageAgentMergeType: SettingKey[Boolean]
Description: whether native-image-agent should merge generated
configurations.
Default: false
Example usage: nativeImageAgentMerge := true
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.
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:
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).Scala
93.9%
Batchfile
6.1%