Hey All, I am trying to configure my build system to allow me to generate older JVM compatible binar...
r
Hey All, I am trying to configure my build system to allow me to generate older JVM compatible binaries with newer JDK releases but am hitting a few snags. I've included details in the thread.
My build environment is running in a Docker container based on
amazoncorretto:21.0.2
. When targetting 21 I have no issues (via
jvmToolchain(21)
and
kotlinOptions { jvmTarget = 21 }
). However, my project requires that in certain deployment situations to create earlier JVM compatible binaries. For example, target compatible with 20. Changing to
jvmToolchain(20)
and
kotlinOptions { jvmTarget = 20 }
results in gradle throwing me the following error:
Copy code
FAILURE: Build failed with an exception.
* What went wrong:
Could not determine the dependencies of task ':compileKotlin'.
> Cannot find a Java installation on your machine matching this tasks requirements: {languageVersion=20, vendor=any, implementation=vendor-specific} for LINUX on x86_64.
   > No locally installed toolchains match and toolchain download repositories have not been configured.
It is my understanding that the JDK should have no problem compiling for compatibility with 20, even if the only available JDK is 21. I assume there is some Gradle-foo I can do to make that happen. Note: I have explicitly disabled gradle from automatically fetching needed JDKs in an effort to not have my CI server downloading a 300+mb blob for every build. I would rather set up multiple docker images, or modify my current one, to include multiple JDKs instead. My current build setup uses: gradle-8.7 kotlin-1.9.23 (targeting language version 1.9) java-21 (trying to also target 20 in certain situations) amazoncorretto:21.0.2 (for build environment)
I may have found a solution by setting all of the following:
Copy code
kotlin {
        jvmToolchain(21) // Installed JDK version
    }
Copy code
compileKotlin {
        kotlinOptions {
            jvmTarget = 20 // Target JDK
        }
    }
Copy code
java {
        sourceCompatibility = JavaVersion.toVersion(20) // Target JDK
        targetCompatibility = JavaVersion.toVersion(20) // Target JDK

        toolchain {
            languageVersion = JavaLanguageVersion.of(21) // Installed JDK version
        }
    }
Inspecting the generated
.class
files seems to indicate everything is compiled to target
major version: 64
, which is what I am looking for.
1
c
The key is in this error message:
No locally installed toolchains match and toolchain download repositories have not been configured.
…Java 20 is not installed on that container, and you haven’t configured Gradle to download JVMs. Try this in `settings.gradle.kts`:
Copy code
plugins {
    id("org.gradle.toolchains.foojay-resolver-convention") version "0.8.0"
}
1
In the absence of letting Gradle download/install the necessary JDKs, you can of course install them locally and either configure Gradle to find them or place them where they can be auto-detected. (docs) Toolchains work by using the specified JDK version - this is in contrast to sourceCompatibility/targetCompatiblity, which have some rough edges resulting in API-incompatible builds.
m
I can recommend https://jakewharton.com/build-on-latest-java-test-through-lowest-java/ which explains why the setup you described is the proper one. There is no value in installing lower java version, even if it's done automatically via
foojay-resolver-convention
plugin
👍 1
💯 1
Moreover, instead of setting not generally advised `sourceCompatibility`/`targetCompatibility` options you may want to use
release
option - documentation
👍 1
For more details on configuring kotlin compilation tasks I can link to https://jakewharton.com/kotlins-jdk-release-compatibility-flag/ which explains how to configure things correctly and how work around the lack of https://youtrack.jetbrains.com/issue/KT-49746/Support-Xjdk-release-in-gradle-toolchain
r
Thanks all for your input. I have opted to set up a custom Docker container that includes the JDKs we need to target and have configured Gradle to detect them and use them when needed.
2351 Views