I'm trying to get Gradle JVM toolchain working for...
# gradle
a
I'm trying to get Gradle JVM toolchain working for a multi module project. I was never able to get it working without specifying custom launcher for every task.. now I'm having issues getting KSP to use a custom launcher so I'm trying the global approach again. I'm setting this in my root build.gradle.kts:
Copy code
kotlin {
    jvmToolchain {
        (this as JavaToolchainSpec).apply {
            languageVersion.set(JavaLanguageVersion.of(17))
        }
    }
}

java {
    toolchain {
        languageVersion.set(JavaLanguageVersion.of(17))
    }
}
but I'm getting errors like this When I run gradle using Java 8
Copy code
No matching variant of csdisco.athena.common:data:1.5.1 was found. The consumer was configured to find an API of a library compatible with Java 8, preferably in the form of class files, preferably optimized for standard JVMs, and its dependencies declared externally, as well as attribute 'org.jetbrains.kotlin.platform.type' with value 'jvm' but:
             - Variant 'apiElements' capability csdisco.athena.common:data:1.5.1 declares an API of a library, packaged as a jar, preferably optimized for standard JVMs, and its dependencies declared externally, as well as attribute 'org.jetbrains.kotlin.platform.type' with value 'jvm':
                 - Incompatible because this component declares a component compatible with Java 17 and the consumer needed a component compatible with Java 8
             - Variant 'runtimeElements' capability csdisco.athena.common:data:1.5.1 declares a runtime of a library, packaged as a jar, preferably optimized for standard JVMs, and its dependencies declared externally, as well as attribute 'org.jetbrains.kotlin.platform.type' with value 'jvm':
                 - Incompatible because this component declares a component compatible with Java 17 and the consumer needed a component compatible with Java 8
I've tried to specify the kotlin / java toolchain blocks above per project, in allProjects or subProjects but those result in compile errors What is the proper way to configure the toolchain for multi module projects?
h
The error sais you have issues with incompatible java target versions. For example when you use a platform that requires java 8, you cant just use java17. I can't see exactly what your mismatches are, but configuring the target java version has to be done for every subproject that produces jvm stuff, just like you already tried. Lets try again and let us take a look at the compiler errors, they are probably solvable. Is you project public somewhere?
a
No the project is private. My issue is that I build in Jenkins which is running on JDK 1.8 but I have a dependency that is targeting JVM 17
I can solve this with Docker, but when toolchains came out I decided to try it out and speed up my jenkins builds, which it did and worked great.. though my configuration was a bit rough
Copy code
import org.jetbrains.kotlin.gradle.tasks.KotlinCompile

plugins {
    base
    kotlin("jvm")
    id("org.springframework.boot") apply false
    id("io.spring.dependency-management") apply false
    kotlin("plugin.spring") apply false
    kotlin("plugin.serialization") apply false
    id("org.jmailen.kotlinter")
    `version-catalog`
}

tasks.compileJava {
    options.release.set(16)
}

kotlin {
    jvmToolchain {
        (this as JavaToolchainSpec).apply {
            languageVersion.set(JavaLanguageVersion.of("16"))
            vendor.set(JvmVendorSpec.ADOPTOPENJDK)
        }
    }
}

allprojects {

    group = "revenue"


    repositories 
        maven("<https://jitpack.io>")
        maven {
            url = uri("<https://dl.bintray.com/kotlin/ktor>")
        }
        maven {
            url = uri("<https://dl.bintray.com/kotlin/kotlinx>")
        }
    }

}

val service = project.extensions.getByType<JavaToolchainService>()
val customLauncher = service.launcherFor {
    languageVersion.set(JavaLanguageVersion.of("16"))
}


subprojects {
    apply(plugin = "org.jmailen.kotlinter")

    buildDir = File(rootProject.projectDir, "build/gradle/" + project.name)

    tasks.withType<KotlinCompile>().configureEach {
        kotlinOptions {
            jvmTarget = "16"
            freeCompilerArgs = listOf("-Xjsr305=strict", "-Xopt-in=kotlin.RequiresOptIn")
        }
        kotlinJavaToolchain.toolchain.use(customLauncher)
    }

    tasks.withType<JavaCompile>().configureEach {
        options.release.set(16)
    }

    tasks.withType<Test> {
        useJUnitPlatform()
        maxParallelForks = 4
        javaLauncher.set(customLauncher)
    }

    kotlinter {
        ignoreFailures = false
        disabledRules = arrayOf(
            "max_line_length",
            "no-wildcard-imports",
            "parameter-list-wrapping",
            "experimental:argument-list-wrapping",
            "filename"
        )
    }
}

tasks.register("generate") {
    dependsOn(":generator:run")
    finalizedBy(":generated:formatKotlin")
}

tasks.register("generate-tests") {
    dependsOn(":test-generator:run")
    finalizedBy(":core-tests:formatKotlin")
}
This was the configuration that I finally got working in jenkins, running gradle via 1.8.
But now I'm using KSP, and this doesn't work anymore. I can't figure out make KSP use the custom launcher
I posted a similar question in the #ksp channel about that
Also - if I try to specify a target java version, I get a different error
Copy code
Could not determine the dependencies of task ':compileKotlin'.
> Could not resolve all dependencies for configuration ':kotlinCompilerPluginClasspathMain'.
   > The new Java toolchain feature cannot be used at the project level in combination with source and/or target compatibility
This is my attempt at the old project to make KSP use the custom launcher
Copy code
import org.jetbrains.kotlin.gradle.tasks.KotlinCompile

plugins {
    base
    kotlin("jvm")
    id("org.springframework.boot") apply false
    id("io.spring.dependency-management") apply false
    kotlin("plugin.spring") apply false
    kotlin("plugin.serialization") apply false
    id("org.jmailen.kotlinter")
    id("com.google.devtools.ksp")
    `version-catalog`
    idea
}

kotlin {
    jvmToolchain {
        (this as JavaToolchainSpec).apply {
            languageVersion.set(JavaLanguageVersion.of(17))
            vendor.set(JvmVendorSpec.ADOPTOPENJDK)
        }
    }
}

java {
    toolchain {
        languageVersion.set(JavaLanguageVersion.of(17))
        vendor.set(JvmVendorSpec.ADOPTOPENJDK)
    }
}

allprojects {

    group = "revenue"


    repositories {
        maven("<https://jitpack.io>")
        maven {
            url = uri("<https://dl.bintray.com/kotlin/ktor>")
        }
        maven {
            url = uri("<https://dl.bintray.com/kotlin/kotlinx>")
        }
        google()
    }

}

val service = project.extensions.getByType<JavaToolchainService>()
val customLauncher = service.launcherFor {
    languageVersion.set(JavaLanguageVersion.of(17))
}


subprojects {
    apply(plugin = "org.jmailen.kotlinter")

    buildDir = File(rootProject.projectDir, "build/gradle/" + project.name)

    tasks.withType<KotlinCompile>().configureEach {
        kotlinOptions {
            jvmTarget = "17"
            freeCompilerArgs = listOf("-Xjsr305=strict", "-Xopt-in=kotlin.RequiresOptIn")
        }
       kotlinJavaToolchain.toolchain.use(customLauncher)
    }

    tasks.withType<JavaCompile>().configureEach {
        options.release.set(17)
    }

    tasks.withType<com.google.devtools.ksp.gradle.KspTaskJvm> {
        kotlinJavaToolchain.toolchain.use(customLauncher)
    }

    tasks.withType<Test> {
        useJUnitPlatform()
        maxParallelForks = 4
        javaLauncher.set(customLauncher)
    }

    kotlinter {
        ignoreFailures = false
        disabledRules = arrayOf(
            "max_line_length",
            "no-wildcard-imports",
            "parameter-list-wrapping",
            "experimental:argument-list-wrapping",
            "filename"
        )
    }
}

tasks.register("generate") {
    dependsOn(":generator:run")
    finalizedBy(":generated:formatKotlin")
}

tasks.register("generate-tests") {
    dependsOn(":test-generator:run")
    finalizedBy(":core-tests:formatKotlin")
}
t
FYI, toolchain when it is not explicetly specified, also sets
jvmTarget
to be equal to the toolchain target. So, in your case, you just need to set
kotlinOptions.jvmTarget
to all
KotlinCompile
tasks
a
If I remove the launcher I go back to the errors about the api requested 1.8
Copy code
import org.jetbrains.kotlin.gradle.tasks.KotlinCompile

plugins {
    base
    kotlin("jvm")
    id("org.springframework.boot") apply false
    id("io.spring.dependency-management") apply false
    kotlin("plugin.spring") apply false
    kotlin("plugin.serialization") apply false
    id("org.jmailen.kotlinter")
    id("com.google.devtools.ksp")
    `version-catalog`
    idea
}

kotlin {
    jvmToolchain {
        (this as JavaToolchainSpec).apply {
            languageVersion.set(JavaLanguageVersion.of(17))
            vendor.set(JvmVendorSpec.ADOPTOPENJDK)
        }
    }
}

java {
    toolchain {
        languageVersion.set(JavaLanguageVersion.of(17))
        vendor.set(JvmVendorSpec.ADOPTOPENJDK)
    }
}

allprojects {

    group = "revenue"


    repositories {
        maven("<https://jitpack.io>")
        maven {
            url = uri("<https://dl.bintray.com/kotlin/ktor>")
        }
        maven {
            url = uri("<https://dl.bintray.com/kotlin/kotlinx>")
        }
        google()
    }

}

//val service = project.extensions.getByType<JavaToolchainService>()
//val customLauncher = service.launcherFor {
//    languageVersion.set(JavaLanguageVersion.of(17))
//}


subprojects {
    apply(plugin = "org.jmailen.kotlinter")

    buildDir = File(rootProject.projectDir, "build/gradle/" + project.name)

    tasks.withType<KotlinCompile>().configureEach {
        kotlinOptions {
            jvmTarget = "17"
            freeCompilerArgs = listOf("-Xjsr305=strict", "-Xopt-in=kotlin.RequiresOptIn")
        }
       //kotlinJavaToolchain.toolchain.use(customLauncher)
    }

//    tasks.withType<JavaCompile>().configureEach {
//        options.release.set(17)
//    }

//    tasks.withType<com.google.devtools.ksp.gradle.KspTaskJvm> {
//        kotlinJavaToolchain.toolchain.use(customLauncher)
//    }

    tasks.withType<Test> {
        useJUnitPlatform()
        maxParallelForks = 4
       // javaLauncher.set(customLauncher)
    }

    kotlinter {
        ignoreFailures = false
        disabledRules = arrayOf(
            "max_line_length",
            "no-wildcard-imports",
            "parameter-list-wrapping",
            "experimental:argument-list-wrapping",
            "filename"
        )
    }
}

tasks.register("generate") {
    dependsOn(":generator:run")
    finalizedBy(":generated:formatKotlin")
}

tasks.register("generate-tests") {
    dependsOn(":test-generator:run")
    finalizedBy(":core-tests:formatKotlin")
}
Results in :
Copy code
No matching variant of csdisco.athena.common:config:1.5.1 was found. The consumer was configured to find an API of a library compatible with Java 8, preferably in the form of class files, preferably optimized for standard JVMs, and its dependencies declared externally, as well as attribute 'org.jetbrains.kotlin.platform.type' with value 'jvm' but:
             - Variant 'apiElements' capability csdisco.athena.common:config:1.5.1 declares an API of a library, packaged as a jar, preferably optimized for standard JVMs, and its dependencies declared externally, as well as attribute 'org.jetbrains.kotlin.platform.type' with value 'jvm':
                 - Incompatible because this component declares a component compatible with Java 17 and the consumer needed a component compatible with Java 8
             - Variant 'runtimeElements' capability csdisco.athena.common:config:1.5.1 declares a runtime of a library, packaged as a jar, preferably optimized for standard JVMs, and its dependencies declared externally, as well as attribute 'org.jetbrains.kotlin.platform.type' with value 'jvm':
                 - Incompatible because this component declares a component compatible with Java 17 and the consumer needed a component compatible with Java 8
      > Could not resolve csdisco.athena.common:data:1.5.1.
Copy code
The consumer was configured to find an API of a library compatible with Java 8
Toolchain is set to 17, but this is still referencing the JDK version I called gradle with
t
could you post consumer
build.gradle.kts
here?
a
Copy code
plugins {
    kotlin("jvm")
}

dependencies {

    implementation(libs.bundles.kotlin)
    implementation(libs.logging)
    implementation(libs.bundles.jackson)
    implementation(athenaCommon.config)
    implementation(athenaCommon.data)
    implementation(libs.datadog.statsd.client)

}
I'm using version catalog
t
wait, if posted above is the root
build.gradle.kts
- you are applying toolchain only to this module. You need to apply toolchain for every JVM module
a
Ok
So I suspected that was an issue
t
also you don't need to configure both Kotlin and Java toolchains - they are equal and configure each other
just one of them would be enough
a
Ok
Can I set the JVM Toolchain in allProjects or subProjects? All my attempts result in compiler failures
complaining kotlin extension doesn't exist
Copy code
Extension with name 'kotlin' does not exist. Currently registered extension names: [ext, kotlinter]
adding this to the top of subProjects gives me this
Copy code
apply(plugin = "kotlin")
Copy code
* What went wrong:
An exception occurred applying plugin request [id: 'org.gradle.java-platform']
> Failed to apply plugin 'org.gradle.java-platform'.
   > The "java-platform" plugin cannot be applied together with the "java" (or "java-library") plugin. A project is either a platform or a library but cannot be both at the same time.
I'm using java-platform to import jackson and aws bom's
t
something like this may work:
Copy code
subprojects {
   it.extensions.configure<KotlinTopLevelExtension> {
       jvmToolchain { ... }
   }
}
a
Ah - I saw something similar to that in the kotlin codebase while trying to figure out how it configures it
Copy code
Extension of type 'KotlinTopLevelExtension' does not exist. Currently registered extension types: [ExtraPropertiesExtension, KotlinterExtension]
t
Then try:
Copy code
subprojects {
   it.plugins.withId("org.jetbrains.kotlin.jvm") {
       it.extensions.configure<KotlinTopLevelExtension> {
          jvmToolchain { ... }
       }
   }
}
a
Ok back to the kspFailure now
Copy code
e: java.lang.UnsupportedClassVersionError: csdisco/athena/revenue/core/metrics/processor/MetricsAnnotationProcessorProvider has been compiled by a more recent version of the Java Runtime (class file version 61.0), this version of the Java Runtime only recognizes class file versions up to 52.0
t
this means
csdisco/athena/revenue/core/metrics/processor/MetricsAnnotationProcessorProvider
was compiled with target higher then KSP is running on
a
Yeah KSP isn't picking up the toolchain I suspect
t
yep, it requires plugin authors to add such support
mm, looking at a sources I see KSP extends Kotlin plugin tasks. Could you share the code or run
./gradlew help --task <ksp_task_name>
?
a
Copy code
./gradlew help --task kspKotlin
Type-safe dependency accessors is an incubating feature.
Type-safe project accessors is an incubating feature.

> Task :help
Detailed task information for kspKotlin

Paths
     :annotation-processor:kspKotlin
     :models:metrics:kspKotlin

Type
     KspTaskJvm (com.google.devtools.ksp.gradle.KspTaskJvm)

Description
     -

Group
     -
t
which KSP version are you using?
a
Copy code
kspVersion=1.6.0-1.0.1
t
then it should pickup toolchain 🤔
could you share full stacktrace?
a
Yeah - I thought so too.. with KAPT I was able to get it working by setting the custom launcher
t
kapt tasks should pickup toolchain via extension configuration as well
a
I tried this:
Copy code
tasks.withType<com.google.devtools.ksp.gradle.KspTaskJvm> {
        kotlinJavaToolchain.toolchain.use(customLauncher)
    }
Yeah much better without the custom launcher now
But that still should have worked, I thought.
Copy code
> Task :models:metrics:kspKotlin FAILED
e: java.lang.UnsupportedClassVersionError: csdisco/athena/revenue/core/metrics/processor/MetricsAnnotationProcessorProvider has been compiled by a more recent version of the Java Runtime (class file version 61.0), this version of the Java Runtime only recognizes class file versions up to 52.0
        at java.lang.ClassLoader.defineClass1(Native Method)
        at java.lang.ClassLoader.defineClass(ClassLoader.java:757)
        at java.security.SecureClassLoader.defineClass(SecureClassLoader.java:142)
        at java.net.URLClassLoader.defineClass(URLClassLoader.java:473)
        at java.net.URLClassLoader.access$100(URLClassLoader.java:74)
        at java.net.URLClassLoader$1.run(URLClassLoader.java:369)
        at java.net.URLClassLoader$1.run(URLClassLoader.java:363)
        at java.security.AccessController.doPrivileged(Native Method)
        at java.net.URLClassLoader.findClass(URLClassLoader.java:362)
        at java.lang.ClassLoader.loadClass(ClassLoader.java:419)
        at java.lang.ClassLoader.loadClass(ClassLoader.java:352)
        at java.lang.Class.forName0(Native Method)
        at java.lang.Class.forName(Class.java:348)
        at org.jetbrains.kotlin.cli.jvm.plugins.ServiceLoaderLite.loadImplementations(ServiceLoaderLite.kt:51)
        at org.jetbrains.kotlin.cli.jvm.plugins.ServiceLoaderLite.loadImplementations(ServiceLoaderLite.kt:44)
        at com.google.devtools.ksp.KotlinSymbolProcessingExtension.loadProviders(KotlinSymbolProcessingExtension.kt:68)
        at com.google.devtools.ksp.AbstractKotlinSymbolProcessingExtension.doAnalysis(KotlinSymbolProcessingExtension.kt:161)
        at org.jetbrains.kotlin.cli.jvm.compiler.TopDownAnalyzerFacadeForJVM.analyzeFilesWithJavaIntegration(TopDownAnalyzerFacadeForJVM.kt:120)
        at org.jetbrains.kotlin.cli.jvm.compiler.TopDownAnalyzerFacadeForJVM.analyzeFilesWithJavaIntegration$default(TopDownAnalyzerFacadeForJVM.kt:96)
        at org.jetbrains.kotlin.cli.jvm.compiler.KotlinToJVMBytecodeCompiler$analyze$1.invoke(KotlinToJVMBytecodeCompiler.kt:262)
        at org.jetbrains.kotlin.cli.jvm.compiler.KotlinToJVMBytecodeCompiler$analyze$1.invoke(KotlinToJVMBytecodeCompiler.kt:53)
        at org.jetbrains.kotlin.cli.common.messages.AnalyzerWithCompilerReport.analyzeAndReport(AnalyzerWithCompilerReport.kt:113)
        at org.jetbrains.kotlin.cli.jvm.compiler.KotlinToJVMBytecodeCompiler.analyze(KotlinToJVMBytecodeCompiler.kt:253)
        at org.jetbrains.kotlin.cli.jvm.compiler.KotlinToJVMBytecodeCompiler.compileModules$cli(KotlinToJVMBytecodeCompiler.kt:100)
        at org.jetbrains.kotlin.cli.jvm.compiler.KotlinToJVMBytecodeCompiler.compileModules$cli$default(KotlinToJVMBytecodeCompiler.kt:58)
        at org.jetbrains.kotlin.cli.jvm.K2JVMCompiler.doExecute(K2JVMCompiler.kt:170)
        at org.jetbrains.kotlin.cli.jvm.K2JVMCompiler.doExecute(K2JVMCompiler.kt:52)
        at org.jetbrains.kotlin.cli.common.CLICompiler.execImpl(CLICompiler.kt:92)
        at org.jetbrains.kotlin.cli.common.CLICompiler.execImpl(CLICompiler.kt:44)
        at org.jetbrains.kotlin.cli.common.CLITool.exec(CLITool.kt:98)
        at org.jetbrains.kotlin.daemon.CompileServiceImpl.compile(CompileServiceImpl.kt:1618)
        at sun.reflect.GeneratedMethodAccessor104.invoke(Unknown Source)
        at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
        at java.lang.reflect.Method.invoke(Method.java:498)
        at sun.rmi.server.UnicastServerRef.dispatch(UnicastServerRef.java:357)
        at sun.rmi.transport.Transport$1.run(Transport.java:200)
        at sun.rmi.transport.Transport$1.run(Transport.java:197)
        at java.security.AccessController.doPrivileged(Native Method)
        at sun.rmi.transport.Transport.serviceCall(Transport.java:196)
        at sun.rmi.transport.tcp.TCPTransport.handleMessages(TCPTransport.java:573)
        at sun.rmi.transport.tcp.TCPTransport$ConnectionHandler.run0(TCPTransport.java:834)
        at sun.rmi.transport.tcp.TCPTransport$ConnectionHandler.lambda$run$0(TCPTransport.java:688)
        at java.security.AccessController.doPrivileged(Native Method)
        at sun.rmi.transport.tcp.TCPTransport$ConnectionHandler.run(TCPTransport.java:687)
        at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1149)
        at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:624)
        at java.lang.Thread.run(Thread.java:748)
t
Sounds like a bug in Kotlin compiler 🤔 Could you make a repro project and file an issue?
a
ok
🙏 1
in ksp or the kotlin repo ?
t
a
ok will do
Thanks again for your help! @tapchicoma
3716 Views