When trying to use the Kotlin Gradle plugin `1.7.0...
# gradle
j
When trying to use the Kotlin Gradle plugin
1.7.0-RC
in a buildSrc project, the
kotlin-dsl
plugin cannot be applied. Is there any way I can already use
1.7.0-RC
- or is it just not possible yet? The exception is:
Copy code
Caused by: java.lang.NoSuchFieldError: Companion
	at org.jetbrains.kotlin.gradle.dsl.ToolchainSupport$Companion.createToolchain$kotlin_gradle_plugin(ToolchainDsl.kt:33)
	at org.jetbrains.kotlin.gradle.dsl.KotlinTopLevelExtension.<init>(KotlinProjectExtension.kt:66)
	at org.jetbrains.kotlin.gradle.dsl.KotlinProjectExtension.<init>(KotlinProjectExtension.kt:106)
e
no, Gradle's kotlin-dsl is tied to Gradle's embedded Kotlin version
c
which maxes out at 1.5.31 for currently released versions of Gradle. Gradle 7.5 (not yet released) may allow that to be 1.6.2x. Generally one is either writing a Gradle Kotlin DSL plugin (using
kotlin-dsl
and the Gradle-compatible/provided Kotlin versions), or a Kotlin library/application using the Kotlin Gradle plugin. It’s nonsensical to mix the two in a given project.
j
Oh I see, now that you say it I don't even know why I applied the kotlin-gradle-plugin to a project where the kotlin-dsl plugin was already present, thanks for the hint! I guess I can just use 1.5.31 (via kotlin-dsl) in buildSrc and still have the rest of the project use
1.7.0-RC
?
e
yes
c
correct. to set the Kotlin language level about 1.4 (the default) you will need this:
Copy code
afterEvaluate {
            tasks.withType<KotlinCompile>().configureEach {
                kotlinOptions {
                    // arg necessary to address <https://github.com/gradle/gradle/issues/17052>
                    freeCompilerArgs += "-Xsam-conversions=class"
                    apiVersion = "1.5"
                    languageVersion = "1.5"
                }
            }
        }
…note the dreaded
afterEvaluate
which is required in the case (always try to avoid this!!!), as the Kotlin DSL plugin sets the language level to 1.4 in its own
afterEvaluate
.
e
don't do that, there's a kotlinDslPluginOptions extension
oh language version not target JVM… well ok
c
yea. and the compiler arg. elsewhere doing:
Copy code
configure<KotlinDslPluginOptions> {
            jvmTarget.set(kotlinPluginJvmVersion.toString())
        }
j
which maxes out at 1.5.31 for currently released versions of Gradle
So it is basically impossible to write precompiled scripts (with the Gradle Kotlin DSL extensions) in buildSrc with up to date ksp, dokka versions and so on? Seems like the only solution is to just not use the kotlin-dsl plugin here, but then the scripts would become much more verbose.
e
if you are writing a Gradle plugin, with or without
kotlin-dsl
, it will run in the Gradle environment which will force the usage of Gradle's embedded Kotlin. so no, you cannot use the latest Kotlin.
j
I see, so seems like buildSrc (or includedBuilds in general) are not what I actually want here? If I want to split up Kotlin build scripts and make them generally available for all modules, what would be the better solution there? I have to be able to use the other (up-to-date) Kotlin compiler plugins inside these scripts.
e
if you are writing build scripts, then they will need to be compatible with Gradle's embedded environment. this is not exclusive to Kotlin, https://github.com/gradle/gradle/issues/17375
includeBuild can use any version of Kotlin if they're being used as normal dependencies. but when they are used as buildscript dependencies/plugins, yes they are subject to similar limitations as buildSrc
j
I know, I meant in my normal application buildscript, I of course am able to use the ksp plugin for Kotlin 1.7.0-RC, as well as the kotlinx.serialization plugin for that version and so on - even though the embedded Kotlin version of Gradle is much older. But it is not possible inside buildSrc and any other included build. So I was wondering whether there is an alternative to includeBuild which is similar in the way it allows me to split up my build setup, but does not work with precompiled build scripts which then have to applied as plugins?
e
not without shadowing, no
but there is no issue in having includeBuild use a different version of Kotlin and plugins than your main build
j
well there is, as I said I want to use ksp in the scripts there, and the ksp version has to match the kotlin version of my main build
e
I don't see why the second part of your statement is true. you can use different KSP plugin versions in different builds (including includeBuild)
j
The plugin version used in buildSrc cannot be overwritten later as far as I can tell.
e
buildSrc might be special, I haven't checked. but includeBuild should not have any issues.
j
oh if that's true it would be great, I'll check
e
just to be clear, you mean using
plugins { id("...ksp") }
inside
buildSrc/build.gradle.kts
, not inside
buildSrc/src/main/kotlin/my-plugin.gradle.kts
? because the latter is fine
j
I applied ksp to the dependencies block inside the first script, so in ``buildSrc/build.gradle.kts``
e
as in
Copy code
// buildSrc/build.gradle.kts
repositories { ... }
dependencies {
    implementation("...ksp-gradle-plugin...")
}
? as long as you're not applying the plugin the the
buildSrc
project itself, that is totally fine
j
yes, like in your snippet
message has been deleted
e
works completely fine for me
j
so what I now basically have to do is to use an older ksp version in the included build and a newer ksp version in the main build?
e
are you applying KSP to the included build itself, or simply bringing it in as a dependency to use in another buildscript?
j
the latter
e
I just created a test build with
Copy code
// buildSrc/build.gradle.kts
repositories {
    google()
    mavenCentral()
}

dependencies {
    implementation("com.android.tools.build:gradle:7.2.0")
    implementation(kotlin("gradle-plugin", "1.6.10"))
    implementation("com.google.devtools.ksp:com.google.devtools.ksp.gradle.plugin:1.6.10-1.0.4")
}
and that works fine, for using Kotlin 1.6.10 and KSP 1.6.10-1.0.4 plugins in the main build
you can't apply Kotlin 1.6.10 to the buildSrc build, but Kotlin 1.6.10's Gradle plugin doesn't use Kotlin 1.6.10 itself - it is compatible with Gradle's version
j
what you have there in your test build is what I had before, but then I updated to 1.7.0-RC
e
I just tried with 1.7.0-RC and 1.7.0-RC-1.0.5 as well
j
but not together with the
kotlin-dsl
plugin, right?
e
oh I see, that does result in buildSrc's older embedded Kotlin compiler being given newer libraries in its compile classpath
honestly that seems like a KSP issue, because Kotlin Gradle plugin is careful with what it uses
basically, KSP should address the equivalent of https://youtrack.jetbrains.com/issue/KT-41142
but as a band-aid,
Copy code
// buildSrc/build.gradle.kts

plugins {
    `kotlin-dsl`
}

repositories {
    google()
    mavenCentral()
}

dependencies {
    implementation("com.android.tools.build:gradle:7.2.0")
    implementation(kotlin("gradle-plugin", "1.7.0-RC"))
    compileOnly("com.google.devtools.ksp:com.google.devtools.ksp.gradle.plugin:1.5.31-1.0.1")
    runtimeOnly("com.google.devtools.ksp:com.google.devtools.ksp.gradle.plugin:1.7.0-RC-1.0.5")
}
works
j
oh I see, that does result in buildSrc's older embedded Kotlin compiler being given newer libraries in its compile classpath
did you get the same
java.lang.NoSuchFieldError: Companion
exception? or are you just referring to the "w: Runtime JAR files in the classpath should have the same version" warning?
honestly that seems like a KSP issue, because Kotlin Gradle plugin is careful with what it uses
seems like it is a very common issue, as it is also the case for dokka and other compiler plugins
e
I'm not referring to the warning, but a hard plugin compile error
m
I stumbled upon this thread and it fixed my issue. I used the compiler plugin to facilitate library usage by providing ksp configuration. One of the things it did was apply the ksp plugin so that user doesn't have to. But then I realized that this is a mistake which couples the ksp version that I use (the one in
runtimeOnly
with my library (and thus with a specific kotlin version). Instead, I'm now requiring the ksp plugin, but not providing it implicitly, so that user can choose his kotlin and ksp version. I'm not sure what the original use case for ksp plugin dependency you had @Jakob K, but wanted to share in case anyone ends up here like me 🙂