Marek
07/22/2025, 7:17 PMkotlin-dsl gradle plugin in an included build that contains convention plugins.
I use latest Gradle 8.14.3
It broke when I wanted to update Kotlin to 2.2.0. My convention plugins are depending on another gradle plugins that the convention plugins are configuring. Dagger and Hilt are the ones that are now failing saying that
Class 'dagger.hilt.android.plugin.HiltExtension' was compiled with an incompatible version of Kotlin. The actual metadata version is 2.2.0, but the compiler version 2.0.0 can read versions up to 2.1.0
Does it mean that gradle kotlin-dsl plugin always uses the kotlin compiler bundled in Gradle and there is a Gradle update required to fix this compatibility issue? Or is there any way to force gradle using newer kotlin for building gradle convention plugins?ephemient
07/22/2025, 8:25 PMMartin
07/22/2025, 11:07 PMorg.jetbrains.kotlin.jvm instead of kotlin-dsl and compile against 2.2 libsVladimir Sitnikov
07/23/2025, 4:46 AMMartin
07/23/2025, 7:14 AMMarek
07/23/2025, 7:54 AMkotlin-dsl to 6.2.0 instead of 5.2.0 that is bundled with gradle 8.14.3 helped as well.
Although Gradle now warns about that.
This version of Gradle expects version '5.2.0' of the `kotlin-dsl` plugin but version '6.2.0' has been applied to project ':gradle:conventions'. Let Gradle control the version of `kotlin-dsl` by removing any explicit `kotlin-dsl` version constraints from your build logic.
WARNING: Unsupported Kotlin plugin version.
The `embedded-kotlin` and `kotlin-dsl` plugins rely on features of Kotlin `2.0.21` that might work differently than in the requested version `2.2.0`.Martin
07/23/2025, 8:03 AMid("org.gradle.kotlin.kotlin-dsl") version "6.2.0"Martin
07/23/2025, 8:04 AMMartin
07/23/2025, 8:05 AMMarek
07/23/2025, 8:07 AMgradlePlugin block for defining plugins comes from the kotlin-dsl .
And additionally I rely on some legacy groovy code and had to change the compilations dependency by doing
fun setupLanguageDependencies() {
tasks.compileGroovy.configure {
classpath = sourceSets.main.get().compileClasspath
}
tasks.compileKotlin.configure {
libraries.from(sourceSets.main.get().groovy.classesDirectory)
}
}Martin
07/23/2025, 8:34 AMVampire
07/23/2025, 9:08 AMSince theIt is notblock for defining plugins comes from thegradlePlugin.kotlin-dsl
Vampire
07/23/2025, 9:08 AMVampire
07/23/2025, 9:09 AMMarek
07/23/2025, 9:09 AMMarek
07/23/2025, 9:09 AMMarek
07/23/2025, 9:12 AMMartin
07/23/2025, 9:12 AMkotlin-dsl configures the annotation for youMartin
07/23/2025, 9:12 AMplugins {
id("org.jetbrains.kotlin.jvm").version("2.2.0")
id("org.jetbrains.kotlin.plugin.sam.with.receiver").version("2.2.0")
}
samWithReceiver {
annotation(HasImplicitReceiver::class.qualifiedName!!)
}
?Marek
07/23/2025, 9:13 AMMartin
07/23/2025, 9:14 AMAction<> (which is used inside AGP)Marek
07/23/2025, 9:14 AMMartin
07/23/2025, 9:16 AMkotlin-dsl code is here if you want to look into what it's doing/take the parts that you are interested inMarek
07/23/2025, 9:31 AMkotlin.jvm . Thanks. Fantastic piece of work this article of yours @MartinVladimir Sitnikov
07/23/2025, 1:24 PMapiVersion=1.9 and languageVersion=1.9 , however they did not configure it consistently. I’ve explained the details in https://github.com/google/dagger/issues/4848#issuecomment-3108369445Vladimir Sitnikov
07/23/2025, 1:27 PMIf you’re looking for a sample plugin that does’t useOh, dear. nmcp uses gratatouille which is, well, quite a different way of writing Gradle plugins., nmcp is a good example.kotlin-dsl
Martin
07/23/2025, 1:29 PMVladimir Sitnikov
07/23/2025, 1:30 PMVladimir Sitnikov
07/23/2025, 1:30 PMMartin
07/23/2025, 1:30 PMMartin
07/23/2025, 1:32 PMkotlin-dsl though. It removes the need for worker boilerplate and provides classloader isolation. For all the rest, it uses plain regular Kotlin..Martin
07/23/2025, 1:33 PMkotlin-dsl if you want to (although I won't encourage it)Vladimir Sitnikov
07/23/2025, 1:40 PMkotlin-dsl started in 2017 or earlier (it is 8+years already?), so let’s account for that as well.
2. fragmenting the ecosystem by adding sam conversion for Action. Frankly, I would say it converges Groovy and Kotlin scripts. It is great we can have a single method with Action parameter and have both Groovy and Kotlin support lambdas there. Otherwise you’d have to duplicate logic: Clojure for Groovy and ..->.. for Kotlin
3. fragmenting the ecosystem by adding assignment plugin. Once again, I think it converges Groovy and Kotlin, and it reduces the noise in the build scripts
4. it is slow (reference to 3-year-old benchmarks from 2022)
5. it’s stuck on older tools <-- this is very valid
In any case your points 2 and 3 blame kotlin-dsl for “fragmenting the ecosystem by adding the second option to write the same thing”.
What I said above was exactly the same with Gratatouille: it adds yet another language to create Gradle plugins, and it adds a framework to execute Gradle plugins. If “kotlin-dsl is bad for fragmenting the ecosystem”, then the same applies to Gratatouille. If Gratatouille is not bad for “fragmenting the ecosystem by adding yet another language for Gradle plugins”, then “kotlin-dsl” is not bad either.Martin
07/23/2025, 1:42 PMMartin
07/23/2025, 1:43 PMorg.jetbrains.kotlin.jvm but not Gratatouille. If you have another simpler example, I'll definitely update the post as it's true there is some cognitive load to gratatouilleMartin
07/23/2025, 1:44 PMMartin
07/23/2025, 1:45 PMVampire
07/23/2025, 1:54 PMFor 4. we need more benchmarks but there is definitely more work involved with precompiled scripts so it can't be faster.Depends on whether you use precompiled script plugins actually. 🙂 Kotlin DSL precompiled script plugins are just one part of what
kotlin-dsl plugin does.
The added kotlinDsl() dependency and the configured Kotlin Compiler plugins can be used in normal Kotlin files without ever using any precompiled script plugin, and I'd guess that the performance drain for seeing no precompiled Kotlin DSL script plugins are used is neglectible hopefully. 🙂
Besides the ecosystem-split you two are a bit talking about different things I'd say.
I think Martin is more focussed on Gradle plugin code, Vladimir on build scripts.
And actually the point is vaguely moot, because in build scripts you will anyway have these compiler plugins enabled to converge Groovy DSL and Kotlin DSL.
So even if no plugin in the world would use kotlin-dsl, or rather those two compiler plugins, you would still have that "split".
tAnd actually, by not usingMoreover, without using those two compiler plugins you cannot use the syntax that you can use in build scripts within the plugin code, so imho it is better to use those compiler plugins because then you can use the same syntax you use in Kotlin DSL build scripts also in Kotlin written plugins. 🙂Martin
07/23/2025, 1:57 PMkotlin-dsl you would have this invariant:
• .kt => regular Kotlin
• .gradle.kts => Gradle flavored Kotlin
I'd be Martin
07/23/2025, 1:57 PMkotlin-dsl should enforce that everyone uses precompiled scripts pluginsephemient
07/23/2025, 2:04 PMVampire
07/23/2025, 2:05 PMI'd beYou might be, I would hate it by heart. 😄completelymostly fine with this
Vampire
07/23/2025, 2:06 PMkotlin-dsl should enforce that everyone uses precompiled scripts plugins
Why by whoevers sake should such a major restriction be implemented? o_OMartin
07/23/2025, 2:07 PMMartin
07/23/2025, 2:08 PMkotlin-dsl but without the precompiled scripts plugins and with a configurable Kotlinc versionVampire
07/23/2025, 2:08 PMVampire
07/23/2025, 2:08 PMkotlin-dsl 😄Martin
07/23/2025, 2:09 PMkotlin-dsl ?Vladimir Sitnikov
07/23/2025, 2:10 PMVampire
07/23/2025, 2:11 PMI'm lost. Can you configure your kotlinc version withI don't think so, messages are out of order, that was intended before your kotlinc message
Martin
07/23/2025, 2:12 PMMartin
07/23/2025, 2:12 PMkotlin-gradle-plugin pluginVampire
07/23/2025, 2:16 PMVampire
07/23/2025, 2:16 PMephemient
07/23/2025, 2:18 PMkotlin-dsl.precompiled-script-pluginsVampire
07/23/2025, 2:19 PMkotlin-dsl without precompiled script plugins can already be done.
Just apply java-gradle-plugin and kotlin-dsl-base plugins.
Applying these two and additionally the kotlin-dsl-precompiled-script-plugin is all that the kotlin-dsl plugin does, besides checking whether the version is the one expected by current Gradle version.ephemient
07/23/2025, 2:23 PMVampire
07/23/2025, 2:31 PMkotlin-dsl-base plugin is doing (which includes applying the embedded kotlin plugin version), you could also instead apply the org.gradle.kotlin.kotlin-dsl.compiler-settings plugin which adds and configures the compiler plugins and add the gradleKotlinDsl() dependency manually to compileOnly and testImplementation. That is, what the base plugin is doing in addition to applying the embedded kotlin plugin version. You probably would have to first add the KotlinDslPluginOptions extension though I think. Iirc the base plugin would do that and the compiler settings plugin requires it to be there.