From f494dc6815e5c75de3313073a38454aec13f12e3 Mon Sep 17 00:00:00 2001 From: Walter Oggioni Date: Mon, 23 Oct 2023 16:53:40 +0800 Subject: [PATCH] added documentation of NativeImage plugin --- graalvm/REAMDE.md | 132 ++++++++++++++++++ .../graalvm/NativeImageConfigurationTask.java | 26 +++- .../gradle/graalvm/NativeImageTask.java | 2 +- gradle.properties | 2 +- 4 files changed, 154 insertions(+), 8 deletions(-) create mode 100644 graalvm/REAMDE.md diff --git a/graalvm/REAMDE.md b/graalvm/REAMDE.md new file mode 100644 index 0000000..fbd6fc1 --- /dev/null +++ b/graalvm/REAMDE.md @@ -0,0 +1,132 @@ +## Overview +This project contains 2 Gradle plugin: +- NativeImage allows you to create a native executable file from a Gradle project using GraalVM's `native-image` tool +- Jlink allows you to create a native distribution of a Gradle project using GraalVM `jlink` tool + +### Native Image plugin + +Declare the plugin in your build's `settings.gradle` like this +```groovy + +pluginManagement { + repositories { + maven { + url = 'https://woggioni.net/mvn/' + } + } + + plugins { + id "net.woggioni.gradle.graalvm.native-image" version "2023.10.23" + } +} +``` + +Then add it to a project's `build.gradle` + +```groovy +plugins { + id 'net.woggioni.gradle.graalvm.native-image' +} + +configureNativeImage { + args = [ 'your', 'command', 'line', 'arguments'] +} + +application { + mainClass = 'your.main.Class' +} +``` +Mind that if your project also uses the built-in Gradle `application` plugin, that must be applied before the `net.woggioni.gradle.graalvm.native-image`. + +The plugin adds 2 tasks to your project: + +- `configureNativeImage` of type `net.woggioni.gradle.graalvm.NativeImageConfigurationTask` which launches + your application with the [native-image-agent](https://www.graalvm.org/latest/reference-manual/native-image/metadata/AutomaticMetadataCollection/) + to generate the native image configuration files in `${project.projectDir}/native-image` +- `nativeImage` of type `net.woggioni.gradle.graalvm.NativeImageTask` that creates the native executable the project's + libraries folder (`${project.buildDir}/libs`) + +#### Configuration for `NativeImageConfigurationTask` + +###### mergeConfiguration + +This boolean property decides whether to create a new set of configuration files or simply append to the existing ones + +#### Configuration for `NativeImageTask` + +###### mainClass + +The name of the main class the native executable will launch, defaults to the value set in + +```groovy +application { + mainClass = 'my.main.class' +} +``` + +###### mainModule + +The name of the main JPMS module the native executable will launch, defaults to the value set in + +```groovy +application { + mainModule = 'my.main.module' +} +``` + +Only applicable when `useJpms` is true + +###### useJpms + +Whether or not enable JPMS in the generated executable +(dependencies that support JPMS will be forwarded to `native-image` using the `-p` instead of the `-cp` option) + +###### useMusl + +This boolean property allows to link the generated executable to musl libc, +note that in order to do that a valid (linked to musl-libc) compiler toolchain must be available +on the `PATH`, for example if building x86_64 executables on Linux, GraalVM will look for +`x86_64-linux-musl-gcc` + +###### buildStaticImage + +This boolean property allows to create a statically linked executable for maximum portability +(a static executable only depends on the kernel and can be moved freely to +another different machine with the same operating system and CPU architecture). +Beware that this requires the libc to support static linking +(most notably, the glibc does not support static linking, the only way to build static executables +on linux is to link to a different libc implementation like musl libc). + +###### enableFallback + +Whether or not to allow the creation of the [fallback image](https://www.graalvm.org/22.0/reference-manual/native-image/Limitations/) +when native-image configuration is missing. + +###### graalVmHome + +This points to the installation folder of GraalVM, defaults to the installation directory +of the selected Gradle toolchain (if any) or the installation directory +of the JVM Gradle is running on otherwise. + +#### Customize native-image command line +A [native-image.properties](https://www.graalvm.org/22.0/reference-manual/native-image/BuildConfiguration/) +file can be added to `${project.projectDir}/native-image` to add custom parameters: + +```bash +-H:Optimize=3 --initialize-at-run-time=your.main.class --gc=G1 +``` + +#### Limitations + +GraalVM with the [native-image](https://www.graalvm.org/22.0/reference-manual/native-image/) plugin is required in order +for these plugins to work, this can be achieved either running Gradle under GraalVM directly or using Gradle toolchains +support to request GraalVM at the project level + +```groovy +java { + toolchain { + languageVersion = JavaLanguageVersion.of(17) + vendor = JvmVendorSpec.GRAAL_VM + } +} +``` \ No newline at end of file diff --git a/graalvm/src/main/java/net/woggioni/gradle/graalvm/NativeImageConfigurationTask.java b/graalvm/src/main/java/net/woggioni/gradle/graalvm/NativeImageConfigurationTask.java index 39a7ff6..52ebf1c 100644 --- a/graalvm/src/main/java/net/woggioni/gradle/graalvm/NativeImageConfigurationTask.java +++ b/graalvm/src/main/java/net/woggioni/gradle/graalvm/NativeImageConfigurationTask.java @@ -10,12 +10,14 @@ import org.gradle.api.plugins.JavaPlugin; import org.gradle.api.plugins.JavaPluginExtension; import org.gradle.api.provider.Property; import org.gradle.api.provider.Provider; +import org.gradle.api.tasks.Input; import org.gradle.api.tasks.JavaExec; import org.gradle.api.tasks.OutputDirectory; import org.gradle.api.tasks.TaskContainer; import org.gradle.api.tasks.bundling.Jar; import org.gradle.jvm.toolchain.JavaLauncher; import org.gradle.jvm.toolchain.JavaToolchainService; +import org.gradle.process.CommandLineArgumentProvider; import java.util.ArrayList; import java.util.Collections; @@ -27,6 +29,8 @@ import static net.woggioni.gradle.graalvm.Constants.GRAALVM_TASK_GROUP; import static net.woggioni.gradle.graalvm.NativeImagePlugin.NATIVE_IMAGE_CONFIGURATION_FOLDER_NAME; public abstract class NativeImageConfigurationTask extends JavaExec { + @Input + public abstract Property getMergeConfiguration(); @OutputDirectory public abstract DirectoryProperty getConfigurationDir(); @@ -50,6 +54,7 @@ public abstract class NativeImageConfigurationTask extends JavaExec { } getConfigurationDir().convention(layout.getProjectDirectory() .dir(NATIVE_IMAGE_CONFIGURATION_FOLDER_NAME)); + getMergeConfiguration().convention(true); ConfigurationContainer cc = getProject().getConfigurations(); Configuration runtimeClasspath = cc.getByName(JavaPlugin.RUNTIME_CLASSPATH_CONFIGURATION_NAME); setClasspath(runtimeClasspath); @@ -60,11 +65,20 @@ public abstract class NativeImageConfigurationTask extends JavaExec { runtimeClasspath ) ); - List jvmArgs = new ArrayList<>(); - jvmArgs.add("-agentlib:native-image-agent=config-output-dir=" + getConfigurationDir().get()); - for(String jvmArg : Optional.ofNullable(javaApplication.getApplicationDefaultJvmArgs()).orElse(Collections.emptyList())) { - jvmArgs.add(jvmArg); - } - jvmArgs(jvmArgs); + getJvmArgumentProviders().add(new CommandLineArgumentProvider() { + @Override + public Iterable asArguments() { + List jvmArgs = new ArrayList<>(); + if(getMergeConfiguration().get()) { + jvmArgs.add("-agentlib:native-image-agent=config-merge-dir=" + getConfigurationDir().get()); + } else { + jvmArgs.add("-agentlib:native-image-agent=config-output-dir=" + getConfigurationDir().get()); + } + for(String jvmArg : Optional.ofNullable(javaApplication.getApplicationDefaultJvmArgs()).orElse(Collections.emptyList())) { + jvmArgs.add(jvmArg); + } + return jvmArgs; + } + }); } } diff --git a/graalvm/src/main/java/net/woggioni/gradle/graalvm/NativeImageTask.java b/graalvm/src/main/java/net/woggioni/gradle/graalvm/NativeImageTask.java index cdbc51b..c7ca80e 100644 --- a/graalvm/src/main/java/net/woggioni/gradle/graalvm/NativeImageTask.java +++ b/graalvm/src/main/java/net/woggioni/gradle/graalvm/NativeImageTask.java @@ -87,7 +87,7 @@ public abstract class NativeImageTask extends Exec { javaToolchainService.launcherFor(javaToolchainSpec) ).map(javaLauncher -> javaLauncher.map(JavaLauncher::getMetadata).map(JavaInstallationMetadata::getInstallationPath) - ).orElseGet(() -> layout.dir(project.provider(() ->project.file(System.getProperty("java.home"))))); + ).orElseGet(() -> layout.dir(project.provider(() -> project.file(System.getProperty("java.home"))))); getGraalVmHome().convention(graalHomeDirectoryProvider); BasePluginExtension basePluginExtension = diff --git a/gradle.properties b/gradle.properties index d777abd..1837405 100644 --- a/gradle.properties +++ b/gradle.properties @@ -2,7 +2,7 @@ woggioniMavenRepositoryUrl=https://mvn.woggioni.net/ lys.catalog.version=2023.10.01 -version.myGradlePlugins=2023.10.20 +version.myGradlePlugins=2023.10.23 version.gradle=7.6 version.felix.config.admin=1.9.26 version.felix=7.0.5