micronaut-projects / micronaut-gradle-plugin

A Gradle Plugin for Micronaut
Apache License 2.0
65 stars 43 forks source link

AOT is not aware of the active Java toolchain #1005

Open sgammon opened 4 months ago

sgammon commented 4 months ago

Expected Behavior

Running prepareNativeOptimizations or prepareJitOptimizations should use the same Java toolchain assigned to javaCompile, to avoid issues related to pinned JDKs

Actual Behaviour

AbstractMicronautAotCliTask uses getExecOperations().javaexec(...) without awareness of toolchains; there is no way to assign the javaLauncher or javaCompiler for a AbstractMicronautAotCliTask, and so the user has a choice: disable toolchains and rely on JAVA_HOME, or live with the toolchain the task selects.

In my case, I need GraalVM so that I can pre-optimize my app which uses Truffle. Truffle needs a GraalVM JDK, or a javac/java run enabled with -XX:+EnableJVMCI and --upgrade-module-path. I tried this approach, but was unable to resolve the JAR needed for the GraalVM compiler since Gradle runs the AOT task configuration quite early in the build graph.

Ultimately, the user should have the ability to control the toolchain for the AOT tasks.

Steps To Reproduce

See above

Environment Information

java version "22.0.1" 2024-04-16
Java(TM) SE Runtime Environment Oracle GraalVM 22.0.1+8.1 (build 22.0.1+8-jvmci-b01)
Java HotSpot(TM) 64-Bit Server VM Oracle GraalVM 22.0.1+8.1 (build 22.0.1+8-jvmci-b01, mixed mode, sharing)

Example Application

No response

Version

4.4.0

sgammon commented 4 months ago

For Truffle users, this may surface as:

[To redirect Truffle log output to a file use one of the following options:
* '--log.file=<path>' if the option is passed using a guest language launcher.
* '-Dpolyglot.log.file=<path>' if the option is passed using the host Java launcher.
* Configure logging using the polyglot embedding API.]
[engine] WARNING: The polyglot engine uses a fallback runtime that does not support runtime compilation to native code.
Execution without runtime compilation will negatively impact the guest application performance.
The following cause was found: JVMCI is not enabled for this JVM. Enable JVMCI using -XX:+EnableJVMCI.
For more information see: https://www.graalvm.org/latest/reference-manual/embed-languages/#runtime-optimization-support.
To disable this warning use the '--engine.WarnInterpreterOnly=false' option or the '-Dpolyglot.engine.WarnInterpreterOnly=false' system property.

... emitted from the prepareNativeOptimizations and prepareJitOptimizations tasks.

sgammon commented 4 months ago

cc / @melix @graemerocher

melix commented 3 months ago

There's unfortunately no API in Gradle to figure out if we should use toolchains or not. I think we can workaround by adding one configurable to these tasks. However, your use case is interesting: how do you make a difference between GraalVM and a regular JDK? In Micronaut we've explicitly removed toolchain detection because it's impossible to make the difference so it causes a lot more pain to users than the other way around.

sgammon commented 3 months ago

@melix in our case it would be best to have full control, to be able to set a javaLauncher or javaCompiler. We obtain these from the toolchain APIs manually and then assign them in each task, like compileJava or nativeCompile. As far as I can tell, the AOT tasks are using JavaExec under the hood, but we can't address these tasks to customize them.

It would also cover all use cases of our style to provide some sort of .configure. For example:

tasks.someAotTask {
  javac.configure {
    // runs in the context of a `JavaCompile` task, maybe?
    javaCompiler = myCompilerFromToolchains
  }
}

We are of course happy to work with whatever we can get though :)