badge

Introduction

The Gradle plugin for GraalVM Native Image building adds support for building and testing native images using the Gradle build tool.

Quickstart

Adding the plugin

Add following to plugins section of your project’s build.gradle / build.gradle.kts:

Applying the plugin
plugins {
  // ...

  // Apply GraalVM Native Image plugin
  id 'org.graalvm.buildtools.native' version '0.9.4'
}
plugins {
  // ...

  // Apply GraalVM Native Image plugin
  id("org.graalvm.buildtools.native") version "0.9.4"
}

The plugin isn’t available on the Gradle Plugin Portal yet, so you will need to declare a plugin repository in addition:

Add the following to your settings.gradle / settings.gradle.kts:

Declaring the plugin repository
pluginManagement {
  repositories {
    mavenCentral()
    gradlePluginPortal()
  }
}
pluginManagement {
  repositories {
    mavenCentral()
    gradlePluginPortal()
  }
}
Tip
Testing pre-releases

You can use the development versions of the plugin by adding our snapshot repository instead. Pre-releases are provided for convenience, without any guarantee.

pluginManagement {
    plugins {
        id 'org.graalvm.buildtools.native' version '...'
    }
    repositories {
        maven {
            url "https://raw.githubusercontent.com/graalvm/native-build-tools/snapshots"
        }
        gradlePluginPortal()
    }
}
pluginManagement {
    plugins {
        id("org.graalvm.buildtools.native") version "..."
    }
    repositories {
        maven {
            url = uri("https://raw.githubusercontent.com/graalvm/native-build-tools/snapshots")
        }
        gradlePluginPortal()
    }
}

Installing GraalVM native image tool

The plugin relies on Gradle’s JVM toolchain support, allowing to decorrelate the tool used to run Gradle, the compiler used to build your application, and eventually the SDK used to generate a native image.

In practice, it means that this plugin will try to locate a suitable installation of GraalVM for you, even if you don’t run Gradle itself with GraalVM. For this, it will look into conventional places on your machine, including from installations done by popular tools like SDKMAN! or Jabba.

Warning
Even if you have a GraalVM SDK installed, Gradle will not automatically detect if native-image is also installed. Therefore, you will need to make sure that you have executed gu install native-image as indicated in the setup instructions.

If Gradle cannot find a GraalVM installation on the machine, it will fail with an error like this:

   > No compatible toolchains found for request filter: {languageVersion=11, vendor=matching('GraalVM'), implementation=vendor-specific} (auto-detect true, auto-download true)

This happens because there’s no automatic provisioning of the GraalVM toolchain available yet, so you will have to install it first. Follow the following instructions to install it properly.

Eventually, you also have the options to:

  1. Run Gradle itself with a GraalVM SDK

  2. Setup a GRAALVM_HOME environment variable pointing to your GraalVM installation

Note that none of those options are recommended as they are more fragile.

Configuration

This plugin works with the application plugin and will register a number of tasks and extensions for you to configure.

Available tasks

The main tasks that you will want to execute are:

  • nativeBuild, which will trigger the generation of a native executable of your application

  • nativeRun, which executes the generated native executable

  • nativeTestBuild, which will build a native image with tests found in the test source set

  • nativeTest, which will execute tests found in the test source set in native mode

Those tasks are configured with reasonable defaults respectively by the nativeBuild and nativeTest extensions, which are of type NativeImageOptions.

Native image options

The NativeImageOptions allows you to tweak how the native image is going to be built.

Selecting the GraalVM toolchain

By default, the plugin will select a Java 11 GraalVM toolchain. If you want to use a different toolchain, for example a GraalVM Enterprise Edition for Java 8, you can configure the toolchain like this:

Selecting the GraalVM toolchain
nativeBuild {
  javaLauncher = javaToolchains.launcherFor {
    languageVersion = JavaLanguageVersion.of(8)
    vendor = JvmVendorSpec.matching("GraalVM Enterprise")
  }
}
nativeBuild {
  javaLauncher.set(javaToolchains.launcherFor {
    languageVersion.set(JavaLanguageVersion.of(8))
    vendor.set(JvmVendorSpec.matching("GraalVM Enterprise"))
  })
}

Configuration options

The following configuration options are available for building images:

NativeImageOption configuration
nativeBuild {
  // Main options
  imageName = 'application' // The name of the native image, defaults to the project name
  mainClass = 'org.test.Main' // The main class to use, defaults to the application.mainClass
  debug = true // Determines if debug info should be generated, defaults to false
  verbose = true // Add verbose output, defaults to false
  fallback = true // Sets the fallback mode of native-image, defaults to false
  sharedLibrary = false // Determines if image is a shared library, defaults to false if `java-library` plugin isn't included

  systemProperties = [name1: 'value1', name2: 'value2'] // Sets the system properties to use for the native image builder
  configurationFileDirectories.from(file('src/my-config')) // Adds a native image configuration file directory, containing files like reflection configuration

  // Advanced options
  buildArgs.add('-H:Extra') // Passes '-H:Extra' to the native image builder options. This can be used to pass parameters which are not directly supported by this extension
  jvmArgs.add('flag') // Passes 'flag' directly to the JVM running the native image builder

  // Runtime options
  runtimeArgs.add('--help') // Passes '--help' to built image, during "nativeRun" task

  // Development options
  agent = true // Enables the reflection agent. Can be also set on command line using '-Pagent'

  useFatJar = true // Instead of passing each jar individually, builds a fat jar
}
nativeBuild {
  // Main options
  imageName.set("application") // The name of the native image, defaults to the project name
  mainClass.set("org.test.Main") // The main class to use, defaults to the application.mainClass
  debug.set(true) // Determines if debug info should be generated, defaults to false
  verbose.set(true) // Add verbose output, defaults to false
  fallback.set(true) // Sets the fallback mode of native-image, defaults to false
  sharedLibrary.set(false) // Determines if image is a shared library, defaults to false if `java-library` plugin isn't included

  systemProperties.putAll(mapOf(name1 to "value1", name2 to "value2")) // Sets the system properties to use for the native image builder
  configurationFileDirectories.from(file("src/my-config")) // Adds a native image configuration file directory, containing files like reflection configuration

  // Advanced options
  buildArgs.add("-H:Extra") // Passes '-H:Extra' to the native image builder options. This can be used to pass parameters which are not directly supported by this extension
  jvmArgs.add("flag") // Passes 'flag' directly to the JVM running the native image builder

  // Runtime options
  runtimeArgs.add("--help") // Passes '--help' to built image, during "nativeRun" task

  // Development options
  agent.set(true) // Enables the reflection agent. Can be also set on command line using '-Pagent'


  useFatJar.set(true) // Instead of passing each jar individually, builds a fat jar
}
Note
For options that can be set using command-line, if both DSL and command-line options are present, command-line options take precedence.

Long classpath and fat jar support

Under Windows, it is possible that the length of the classpath exceeds what the operating system supports when invoking the CLI to build a native image. As a consequence, if you are running under Windows, the plugin will automatically shorten the classpath of your project by building a so called "fat jar", which includes all entries from the classpath automatically.

In case this behavior is not required, you can disable the fat jar creation by calling:

Disabling the fat jar creation
nativeBuild {
    useFatJar = false
}
nativeBuild {
    useFatJar.set(false)
}

Alternatively, it is possible to use your own fat jar (for example created using the Shadow plugin) by setting the classpathJar property directly on the task:

Disabling the fat jar creation
tasks.named("nativeBuild") {
    classpathJar = myFatJar
}
tasks.named<BuildNativeImageTask>("nativeBuild") {
    classpathJar.set(myFatJar)
}

When the classpathJar property is set, the classpath property is ignored.

Testing support

This plugin supports running JUnit Platform tests as native images. In other words, tests will be compiled and executed as native code.

Currently, this feature requires the execution of the tests in the classic "JVM" mode prior to the execution of tests in native mode. To execute the tests, execute:

./gradlew nativeTest

Reflection support and running with the native agent

If your project requires reflection, then native-image-agent run might be necessary.

The Gradle plugin makes it easy to generate the required configuration files by injecting the agent automatically for you (this includes, but is not limited to the reflection file).

This should be as easy as appending -Pagent to run and nativeBuild, or test and nativeTest task invocations:

./gradlew -Pagent run # Runs on JVM with native-image-agent.
./gradlew -Pagent nativeBuild # Builds image using configuration acquired by agent.

# For testing
./gradlew -Pagent test # Runs on JVM with native-image-agent.
./gradlew -Pagent nativeTest # Builds image using configuration acquired by agent.

Same can be achieved by setting corresponding DSL option, althought this isn’t recommended as this is a development mode feature only.

The generated configuration files will be found in the ${buildDir}/native/agent-output/${taskName} directory, for example, build/native/agent-output/run.

Javadocs

In addition, you can consult the Javadocs of the plugin.