The Gradle plugin for GraalVM Native Image building adds support for building and testing native images using the Gradle build tool.
For upgrading please take a look at the Changelog.
Add following to plugins
section of your project’s build.gradle
/ build.gradle.kts
:
plugins {
// ...
// Apply GraalVM Native Image plugin
id 'org.graalvm.buildtools.native' version '{gradle-plugin-version}'
}
plugins {
// ...
// Apply GraalVM Native Image plugin
id("org.graalvm.buildtools.native") version "{gradle-plugin-version}"
}
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
:
link:../snippets/gradle/groovy/settings.gradle[role=include]
link:../snippets/gradle/kotlin/settings.gradle.kts[role=include]
Tip
|
Testing pre-releases
You can use development versions of the plugin by adding our snapshot repository instead. Pre-releases are provided for convenience, without any guarantee. link:../snippets/gradle/groovy/settings.gradle[role=include] link:../snippets/gradle/kotlin/settings.gradle.kts[role=include] |
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.
Alternatively, you may choose to:
-
Run Gradle itself with a GraalVM SDK
-
Set up a
GRAALVM_HOME
environment variable pointing to your GraalVM installation
Note that none of the above options is recommended as they are more fragile.
This plugin works with the application
plugin and will register a number of tasks and extensions for you to configure.
The main tasks that you will want to execute are:
-
nativeCompile
, which will trigger the generation of a native executable of your application -
nativeRun
, which executes the generated native executable -
nativeTestCompile
, which will build a native image with tests found in thetest
source set -
nativeTest
, which will execute tests found in thetest
source set in native mode
Those tasks are configured with reasonable defaults using the graalvmNative
extension binaries
container of type NativeImageOptions.
The main executable is configured by the image named main
, while the test executable is configured via the image named test
.
The NativeImageOptions allows you to tweak how the native image is going to be built.
By default, the plugin will select a Java 11 GraalVM toolchain. If you want to use a different toolchain, for example a GraalVM Community Edition for Java 8, you can configure the toolchain like this:
link:../snippets/gradle/groovy/build.gradle[role=include]
link:../snippets/gradle/kotlin/build.gradle.kts[role=include]
Because of limitations in Gradle, the plugin may not be able to properly detect the toolchain. This is the case if, for example, you want to use GraalVM Enterprise or you want to be able to select a particular version of GraalVM.
To work around this problem, you can disable toolchain detection:
link:../snippets/gradle/groovy/build.gradle[role=include]
link:../snippets/gradle/kotlin/build.gradle.kts[role=include]
If you do this, the plugin will search for 2 environment variables: GRAALVM_HOME
and JAVA_HOME
in that order.
If one of them is set, it will assume that it points to a valid GraalVM installation and completely bypass toolchain selection.
Therefore, it becomes your responsibility to make sure that the environment variable points to a JDK that is compatible with your build script requirements (in particular, the language version).
The following configuration options are available for building images:
link:../snippets/gradle/groovy/build.gradle[role=include]
link:../snippets/gradle/kotlin/build.gradle.kts[role=include]
Note
|
For options that can be set using command-line, if both DSL and command-line options are present, command-line options take precedence. |
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:
link:../snippets/gradle/groovy/build.gradle[role=include]
link:../snippets/gradle/kotlin/build.gradle.kts[role=include]
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:
link:../snippets/gradle/groovy/build.gradle[role=include]
link:../snippets/gradle/kotlin/build.gradle.kts[role=include]
When the classpathJar
property is set, the classpath
property is ignored.
This plugin supports running tests on the JUnit Platform as native images. This means that tests will be compiled and executed as native code.
In theory, any TestEngine
supported on the JUnit Platform should be supported by this
plugin as long as the programming language used by the TestEngine
and the programming
language used to write the tests is supported in a GraalVM native image. This plugin
provides explicit support for the JUnit Jupiter and JUnit Vintage test engines, and
support for additional test engines should be possible with custom native configuration.
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
Note
|
This plugin requires JUnit Platform 1.8 or higher. |
There are cases where you might want to disable native testing support:
-
You don’t actually want to run your tests in native mode.
-
Your library or application uses a testing framework that is not supported on the JUnit Platform.
-
You need to use the agent when running tests on the JVM but do not wish to run those same tests in native mode.
In this case, you can disable native testing support by configuring the graalvmNative
extension as follows:
link:../snippets/gradle/groovy/build.gradle[role=include]
link:../snippets/gradle/kotlin/build.gradle.kts[role=include]
It’s common to have multiple test source sets in a Gradle build. Typically, you may have an integration test suite, or a functional test suite, in addition to the unit test suite. The plugin supports running those tests as native binaries too.
For example, imagine that you have a source set named integTest
and that its corresponding test task is named integTest
.
In this case you can register a new native test binary via the graalvmNative
extension:
link:../../../../samples/java-application-with-custom-tests/build.gradle[role=include]
link:../snippets/gradle/kotlin/build.gradle.kts[role=include]
The plugin will then automatically create the following tasks:
-
nativeIntegTestCompile
, to compile a native image using theintegTest
source set -
nativeIntegTest
, to execute the tests in native mode
The same mechanism can be used if you have multiple test tasks for a single test source set, which is often the case with manual test sharding.
If your project requires reflection, classpath resources, dynamic proxies or other features requiring explicit native configuration, it may prove helpful to first run your application or tests using the native-image-agent
.
The Native Image Gradle plugin simplifies generation of 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 the run
and nativeBuild
, or test
and nativeTest
task invocations:
./gradlew -Pagent run # Runs on JVM with native-image-agent.
./gradlew -Pagent nativeCompile # 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.
The agent can also be enabled by setting the corresponding DSL flag; however, that is not recommended since 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
.
Although those files will be automatically used if you run your build with the agent enabled, you should consider reviewing them and adding them to your sources instead.
The native agent can be configured with additional options.
This can be done using the agent
configuration block:
link:../snippets/gradle/groovy/build.gradle[role=include]
link:../snippets/gradle/kotlin/build.gradle.kts[role=include]
You may also define distinct agent options for different images. In the following example, the agent used for instrumentation for the main image has distinct options from the test ones:
link:../snippets/gradle/groovy/build.gradle[role=include]
link:../snippets/gradle/kotlin/build.gradle.kts[role=include]
For each binary (main
and test
), the plugin declares 2 configurations that users or plugin authors can use to tweak the native image compilation classpath:
-
nativeImageCompileOnly
(for themain
binary) andnativeImageTestCompileOnly
(for thetest
binary) can be used to declare dependencies which are only needed at image compilation. -
nativeImageClasspath
(for themain
binary) andnativeImageTestClasspath
(for thetest
binary) are the configurations which are resolved to determine the image classpaths.
The native image "compile only" configurations can typically be used to declare dependencies which are only required when building a native binary, and therefore shouldn’t leak to the classic "JVM" runtime.
For example, you could declare a source set which uses the GraalVM SDK to implement native features. This source set would contain code which is only relevant to native images building:
link:../../../../samples/java-application-with-extra-sourceset/build.gradle[role=include]
link:../../../../samples/java-application-with-extra-sourceset/build.gradle.kts[role=include]
In addition, you can consult the Javadocs of the plugin.