From a471af450324b27945b2edeb754be1744452f173 Mon Sep 17 00:00:00 2001 From: David Nestorovic Date: Wed, 18 Sep 2024 15:34:45 +0200 Subject: [PATCH 1/2] Add Getting Started guide --- GettingStarted.md | 414 ++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 414 insertions(+) create mode 100644 GettingStarted.md diff --git a/GettingStarted.md b/GettingStarted.md new file mode 100644 index 000000000..dff271d07 --- /dev/null +++ b/GettingStarted.md @@ -0,0 +1,414 @@ +# Getting started + +This guideline shows how users can start using Native Image through Native Gradle Plugin. + +## Prerequisites + +- Before starting, make sure that you have GraalVM locally. You can [download Oracle GraalVM from the official website](https://www.graalvm.org/downloads/). +- In order to run Gradle project with older GraalVM versions (like Java 17) you should set `JAVA_HOME` environment variable to point to that release. +- Depending on the Gradle version you are using ([see compatibility matrix](https://docs.gradle.org/current/userguide/compatibility.html)), you may not be able to run your project with just `JAVA_HOME` environment variable configured. +However, in order to run Gradle project with any GraalVM version you should set `GRAALVM_HOME` environment variable to point to whatever GraalVM release you want and `JAVA_HOME` environment variable to point to some older version (like Java 17). +This way, Gradle plugin will build itself with Java specified in `JAVA_HOME` and your project with the version specified in `GRAALVM_HOME`. + +## Enable GraalVM Native Image Gradle Plugin + +In order to use Native Image with Gradle, you must add the following block into your `build.gradle` file inside `plugins` block: + +``` +id 'org.graalvm.buildtools.native' version '0.10.3' +``` + +**Note** that at the time of writing this document, `0.10.3` was the latest Native Build Tools released version. +You can find other released versions [here](https://github.com/graalvm/native-build-tools/releases). + +## Setup testing + +In order to run tests on Native Image, all you have to do is to write your tests under the test source and run `./gradlew nativeTestCompile` to compile tests or `./gradlew nativeTest` (compiles and runs the tests) to execute tests found in the `test` source set. +If the tests are simple, no additional work is required. +However, for some more complex tests, you will probably need some additional metadata to make them work(learn more in the [following section](#setup-metadata-collection)). + +The main configuring point for Native Images you want to build is the `graalvmNative` block that you should add into `build.gradle` file. +You can apply configuring options specific to the main or the test binary (or you can provide options that applies to all binaries) like following: + +``` +graalvmNative { + binaries.main { + // options you want to pass only to the main binary + } + binaries.test { + // options you want to pass only to the test binary + } + binaries.all { + // common options you want to use for both main and test binaries + } +} +``` +In this testing case, you should configure `binaries.test` block. +You can pass build-time and run-time options to the Native Image using: +- `buildArgs.add('')` - You can find more about possible build arguments [here](https://www.graalvm.org/latest/reference-manual/native-image/overview/BuildConfiguration/) +- `runtimeArgs.add('')` - You can find more about possible runtime arguments [here](https://www.graalvm.org/latest/reference-manual/native-image/overview/Options/) + + +## Setup and Collect metadata + +When your tests start to be a bit more complex, things like reflection, resources, serialization, proxies or jni may be required. +Since Native Image has closed world assumption, all of these things must be known in advance during the image build. +The easiest way how this information can be passed to the Native Image is through metadata config file(s) - depending on the GraalVM version you are using, there could be +a single `reachability-metadata.json` file (for newer GraalVM versions) or multiple json files (`reflect-config.json`, `resource-config.json`, `proxy-config.json`, `serialization-config.json`, `jni-config.json`). +To learn more about metadata that Native Image consumes, [see this](https://www.graalvm.org/latest/reference-manual/native-image/metadata/). + +Let's say you want to run the test that loads resource called `resource.txt`, and you don't have entry for that resource in the metadata config file, the resource can't be found during the image runtime. + +To make your tests work while using resources (like in this example) or other metadata, you should either generate metadata configurations or write them manually. +To generate metadata automatically, you can run your tests with the Native Image Agent, that will collect all the metadata your tests require. +To enable the agent (through Native Gradle Plugin) you should either: +* add `-Pagent` flag to the command you are executing +* add the following block to `graalvmNative` block in the `build.gradle`: + +``` +agent { + enabled = true +} +``` + +To generate the metadata file(s) for your `tests` just run: +* `./gradlew test` if you added the agent block to the configuration or `./gradlew -Pagent test` if you didn't. This command runs on JVM with Native Image Agent and collects the metadata. +* `./gradlew nativeTest` if you added the agent block to the configuration or `./gradlew -Pagent nativeTest` if you didn't. This command runs on JVM with the Native Image Agent, collects the metadata and uses it for testing on native-image. + +**Note** that because of some Gradle incompatibilities with newer GraalVM versions, you should probably set `GRAALVM_HOME` environment variable +to the GraalVM version you want to use for your project and `JAVA_HOME` to some older version (for example `JDK21`). +However, Gradle will still pick Native Image Agent from the `JAVA_HOME` (so your `JAVA_HOME` must point to GraalVM installation) unless you add the following into the `test` block inside `build.gradle`: +``` +executable = providers.environmentVariable("GRAALVM_HOME").map { + "$it/bin/java" +}.get() +``` +This way, generated metadata config file(s) will have format that is specified in the GraalVM version (from `GRAALVM_HOME`) you are using. + + +### Configure metadata collection + +Now, as your project grows, you should consider configuring the agent with some additional options to gain more control over the generated metadata. + +The first thing you can configure is the agent mode. +There are three possible agent modes: +* `standard` - only generates metadata without any special processing (this is the default mode). No additional options available. This mode is a **great starting point** in your project development +* `conditional` - entries of the generated metadata will be included in the Native Image only if the condition in the entry is satisfied. This mode is mainly aimed towards **library maintainers** with the goal of reducing overall footprint. Conditional mode consumes following additional options: + * `userCodeFilterPath` - specifies a filter file used to classify classes as user application classes. Generated conditions will only reference these classes. See the [agent filter file example](#agent-filter-file) + * `extraFilterPath` - extra filter used to further filter the collected metadata. See the [agent filter file example](#agent-filter-file) +* `direct` - in this mode user configures the agent completely manually by adding all options with `options.add("