Adds the [Java Toolchain](https://docs.gradle.org/current/userguide/toolchains.html#sec:using-java-toolchains) to replace manual executions:
| Old | New |------|------| | `JAVA` | [JavaLauncher](https://docs.gradle.org/current/javadoc/org/gradle/jvm/toolchain/JavaLauncher.html) | | `JAVAC` | [JavaCompiler](https://docs.gradle.org/current/javadoc/org/gradle/jvm/toolchain/JavaCompiler.html) | | `JAVADOC` | [JavadocTool](https://docs.gradle.org/current/javadoc/org/gradle/jvm/toolchain/JavadocTool.html) | ## Instructions for reviewers The build runs on Windows and Linux (Ubuntu), but the analysis was done on Windows. ### JVM detection and selection The toolchain selects the JDKs to use based on all those that are made available to it. As detailed in the link above, JDKs can come from various sources on the user machine, including being auto-provisioned. The daemon JDK is always available (usually `JAVA_HOME`), and `gradle.properties` made `JDK_HOME` available in #2240. Selection of the toolchain build/worker JDK from all available ones is done internally (as detailed in the link) based on the restrictions configured in the toolchain. I have restricted the major version to that of `jdkVersionInfo` (exact version, not minimum), which is determined by the *build file's JDK resolution*: def envJavaHome = cygpath(System.getenv("JDK_HOME")) if (envJavaHome == null || envJavaHome.equals("")) envJavaHome = cygpath(System.getenv("JAVA_HOME")) def javaHome = envJavaHome == null || envJavaHome.equals("") ? System.getProperty("java.home") : envJavaHome However **the selected toolchain JDK might not be the same as the resolved build's JDK**. The toolchain always prefers the daemon JVM to avoid forking, so if it meets the restrictions, it's selected. Consider the following scenarios: | `JAVA_HOME` | `JDK_HOME` | Selection | |----------------|---------------|------------------------------------------------------| | 25 | 26 | `JDK_HOME` - only is passes the restrictions | | 26 | 25 | `JDK_HOME` - only is passes the restrictions | | 25/26 Path A | 25/26 Path B | `JAVA_HOME` - internal toolchain preference >:( | | 25/26 Path A | 25/26 Path A | `JAVA_HOME`==`JDK_HOME` | For local testing: 1. Stop the daemon with `gradlew --stop`. 2. Show the detected toolchains and detection configuration with `gradlew javaToolchains`. The display order is not the selection preference order necessarily. 3. Find which one is used by running `gradlew :base:compileJava -i --rerun` (fastest execution that still compiles Java) and looking for something like `Compiling with toolchain 'C:\Program Files\Java\jdk-26'` near the end, and compare with step 2. You will also see there `Compiling with JDK Java compiler API` instead of `Compiling with Java command line compiler 'C:\Program Files\Java\jdk-26\bin\javac.exe'` - this is the toolchain replacing the manual executions. If you change your env vars, while the daemon is running, stop it so that it picks up the changes (1) and then verify the changes (2). I think that the 3rd scenario will be very rare in practice, and problems arising from it even more so. See also the related [JDK-8087537](https://bugs.openjdk.org/browse/JDK-8087537), although it's very old, so might be a coincidence that it's still relevant. ### Forking The build specifies `compile.options.fork = true` to force forking. You will see `Compilation mode: forking compiler` (also at the end). If this option is removed and the same JDK can be used for both the daemon and the build (rows 3 and 4 above), you will see `Compilation mode: in-process compilation` because the same JVM is used. If different JDKs are required (rows 1 and 2), you will see `Compilation mode: default, forking compiler` because when the JVMs differ, the default is to fork. It is kept to preserve the current behavior, but isn't strictly necessary. It does help with giving the build JVM its own memory rather than sharing it with the daemon. ### Memory Using the CLI execution, Gradle had no say in memory allocation, and the default 1/4th of physical RAM was used (machine-dependent). When Gradle controls the build JVM, it defaults to 512MB (so does the daemon, but this is unchanged). I tested a full `sdk` build and didn't see a difference in running time, so it probably doesn't matter. It can be configured by adding, e.g., `compile.options.forkOptions.memoryMaximumSize = 2g` in the build file if you want to test it locally. I haven't tested if it's enough when running in the same daemon JVM because currently I'm forcing the forking. ### Native tasks Native tasks such as Decora and Prism still use `executable = JAVA`, which will be resolved from the `JDK_HOME` path. As discussed above, the toolchain might be using a different JDK (of the same major version). --------- - [x] I confirm that I make this contribution in accordance with the [OpenJDK Interim AI Policy](https://openjdk.org/legal/ai). ------------- Commit messages: - Whitespaces - Remove CLI execs - Add the toolchain Changes: https://git.openjdk.org/jfx/pull/2294/files Webrev: https://webrevs.openjdk.org/?repo=jfx&pr=2294&range=00 Issue: https://bugs.openjdk.org/browse/JDK-8391822 Stats: 12 lines in 2 files changed: 6 ins; 4 del; 2 mod Patch: https://git.openjdk.org/jfx/pull/2294.diff Fetch: git fetch https://git.openjdk.org/jfx.git pull/2294/head:pull/2294 PR: https://git.openjdk.org/jfx/pull/2294
