I feel like this is a basic question but I can't f...
# gradle
m
I feel like this is a basic question but I can't find it answered in any documentation. I followed the standard Gradle template to create a Kotlin project, the one that creates three custom plugins (common conventions, etc). It doesn't mention how to change/upgrade the Kotlin version anywhere. It's this one: https://docs.gradle.org/current/samples/sample_building_kotlin_applications_multi_project.html None of the generated files actually specify the Kotlin version, and trying to add such a version just creates a mountain of inexplicable errors. What's the trick?
k
this line is repeated twice too 🤔
Copy code
implementation(platform("org.jetbrains.kotlin:kotlin-bom"))
Usually, that has a version...I think it's an oversight that this line doesn't have a version#
m
I am concerned that it's not an oversight, because setting a version there actually doesn't work reliably. Setting it to 1.7 doesn't work at all and setting it to e.g. 1.6.x creates warnings (but does seem to work).
🤔 1
k
it should work...that's the point of BOM... 🤔
m
Let me try again.
k
1.7 won't work..
j
The sample looks a bit untidy. I think there used to be more versions in it. That line ☝️ serves no purpose right now I think. You should be safely able to. remove all the
kotlin-bom
parts and
kotlin-stdlib
parts from
buildSrc/src/main/kotlin/demo.kotlin-common-conventions.gradle.kts
This is done by the Kotlin plugin automatically these days.
I think you should set the version in
buildSrc/build.gradle.kts
Copy code
dependencies {
    implementation("org.jetbrains.kotlin:kotlin-gradle-plugin:YOUR-VERSION")
}
☝️ 1
m
Yeah, I tried that already. That's one of the things that doesn't work.
Let me try again and I'll get the exact error I get. It's during compilation of the build script plugins.
👍 1
e
It should be set by the kotlin version in your dependency in
buildSrc/build.gradle.kts
buildSrc/build.gradle.kts
Copy code
dependencies {
    implementation("org.jetbrains.kotlin:kotlin-gradle-plugin:1.7.0") // Version here was missing in gradle docs
}
k
also a bit weird that the BOM doesn't control the kotlin plugin version: https://mvnrepository.com/artifact/org.jetbrains.kotlin/kotlin-bom/1.7.0 But I guess because plugins aren't really dependencies?
m
Yeah, that's what I was originally trying before getting stuck. It doesn't work for me:
Copy code
w: Consider providing an explicit dependency on kotlin-reflect 1.7 to prevent strange errors
w: Some runtime JAR files in the classpath have an incompatible version. Consider removing them from the classpath
e: /Users/mike/.gradle/caches/modules-2/files-2.1/org.jetbrains.kotlin/kotlin-stdlib-common/1.7.0/51736992f422993a1e741051bdf3c12801bc1ca1/kotlin-stdlib-common-1.7.0.jar!/META-INF/kotlin-stdlib-common.kotlin_module: Module was compiled with an incompatible version of Kotlin. The binary version of its metadata is 1.7.1, expected version is 1.5.1.
e: /Users/mike/.gradle/caches/modules-2/files-2.1/org.jetbrains.kotlin/kotlin-stdlib/1.7.0/a5f42c684ad9003160ef0d0f693ecf0ba7b13549/kotlin-stdlib-1.7.0.jar!/META-INF/kotlin-stdlib.kotlin_module: Module was compiled with an incompatible version of Kotlin. The binary version of its metadata is 1.7.1, expected version is 1.5.1.
k
seems like KOTLIN_VERSION should be defined in buildSrc/build.gradle.kts and the const should be used for the plugin and bom versions...
e
That looks like gradle's embedded kotlin version is conflicting with the one you're trying to use..
if you upgrade gradle to
7.5-rc-3
it would likely work.. you could also probably fix it by removing something from what is done in buildSrc, I'll have a look at what the buildSrc stuff is doing.. 🙂
m
Yes. That's why I'm confused/stuck. Gradle itself is only tested with Kotlin 1.6 so it makes sense that trying to use Kotlin 1.7 here, in buildSrc, wouldn't work. But then everywhere else I try to change the Kotlin version - just for my project, not build logic - I get Gradle errors of different kinds (mostly telling me I can't do that)
Literally nothing I try works, which is astonishing. How can Gradle have got itself into a state where something as simple as upgrading the compiler it's driving is impossible to figure out!?
e
is your project on github?
m
No, it's proprietary.
k
Gradle has an embedded version of Kotlin...we had that warning when using Kotlin 1.6.x in buildsrc scripts (when Gradle's built-in version was 1.5.31) as well but it wasn't an error... But yeah, I agree 🙂
f
You have to define the Kotlin version in the
build.gradle.kts
of the project containing your script plugin. Inside your script plugin you do not refer to any version.
buildSrc/build.gradle.kts
Copy code
plugins {
    `kotlin-dsl`
}

dependencies {
    api("org.jetbrains.kotlin:kotlin-gradle-plugin:1.7.0")
}

repositories {
    mavenCentral()
    gradlePluginPortal()
}
buildSrc/src/main/kotlin/my-convention.gradle.kts
Copy code
plugins {
    kotlin("jvm") // version is inherited from runtime classpath of project
}

dependencies {
    // No need for Kotlin BOM, automatically applied by `kotlin("jvm")`
    // No need for Kotlin STD, automatically applied by `kotlin("jvm")`
    // Other dependencies go here.
}

repositories {
    mavenCentral()
}
some-project/build.gradle.kts
Copy code
plugins {
    id("my-convention")
}
The warning you posted above is not enough to tell what the problem could be.
👍 2
m
@kenkyee Yeah we've got used to ignoring the half-screenful of warnings that Gradle seems to emit for any Kotlin 1.6 project, even though it's harmless 🙄
💯 1
k
bloody annoying as hell though 😂
f
It's not harmless, the warning is serious. However, if it fails or not is something that depends on whether you are using any new symbols introduced in a newer version of Kotlin, or not. That is why it is a warning and not an error. New language features that go into the JVM bytecode usually have no side effects, because the JVM does not know nothing about Kotlin.
👍 1
m
@Fleshgrinder That's pretty much what I have, yeah. The error is indeed unhelpful but it's all I can get out of it, even --info doesn't show anything more. If I had to guess, I'd guess that one of the gradle plugins being used is also using kotlin internally and there's a conflict. But I don't care about upgrading the build logic to a new Kotlin version, only my own project.
It's "harmless" in the sense that things still compile and unit tests still pass. I've seen lots of Gradle projects with this warning, probably because nobody seems to know how to specify what Kotlin version to use in a project correctly 😞
f
If you didn't do anything then it's the …
Copy code
plugins {
    `kotlin-dsl`
}
… inside
buildSrc/build.gradle.kts
that leads to the warning.
buildSrc
is a special weirdo sub-project and there is nothing you can do about this other than not using
buildSrc
. This is the reason why the Gradle folks want to phase it out. 😉
j
Just to confirm: If I download the sample and set the version to
1.7.0
as suggested here, it builds without any error or warning. Imo the setup is correct (from the Gradle perspective). I don’t think that this has anything to do with Gradle’s built-in Kotlin version in this case. It shouldn’t.
1
m
They want to phase it out?!?!
I only created this project about 14 months ago.
And their docs are still guiding people towards creating such projects.
k
lol...wait until you try turning on config caching and you get to find out how much of your build.gradle files is wrong....
m
@kenkyee Tried and abandoned the attempt already 😞
☠️ 1
v
This is the reason why the Gradle folks want to phase it out
Not really. The warning is serious and can lead to problems. It is not caused by Gradle, it is caused by bad plugins. A plugin has to cope with the Kotlin runtime that is provided and hard fixed by Gradle. To be compatible with a specific Gradle version, the plugin has to also be compatible with the embedded Kotlin version. If the plugin depends on a newer Kotlin version, that is bad. If it depends on some lib that depends on a newer Kotlin version, that is bad. Build logic should not directly or transitively bring in any Kotlin stdlib dependencies as they will conflict with the embedded version.
m
@jendrik Right, so something is conflicting somewhere, but there doesn't seem to be any way to find out what or why or how to fix it short of systematically deleting parts of the build system until it starts working. But then I won't have a working build anymore, hmm.
f
Yes, because it's so weird. To ditch
buildSrc
and get rid of the warning:
settings.gradle.kts
Copy code
includeBuild("gradle/plugins/my-convention")

// Soon to be:
// pluginManagement {
//     includeBuild("gradle/plugins/my-convention")
// }
gradle/plugins/my-convention/build.gradle.kts
Copy code
plugins {
    `kotlin-dsl`
}

dependencies {
    api("org.jetbrains.kotlin:kotlin-gradle-plugin:1.7.0")
}

repositories {
    mavenCentral()
    gradlePluginPortal()
}
The rest is just like above. @jendrik I would have thought so too.
m
I already tried disabling some of the plugins that were obvious suspects like Dokka, but it didn't help.
I could try and disable each and every gradle plugin in turn but there are a lot. Seems easier to give up on the Kotlin 1.7 migration.
e
@mikehearn did you try upgrading to gradle 7.5 rc?
m
@Emil Kantis Thanks for the suggestion - I didn't try that yet. I think I'll wait for Gradle 7.5 to come out and hope that it fixes this, then try again. Thanks for the tip!
j
Because of this:
The binary version of its metadata is 1.7.1, expected version is 1.5.1.
I would suspect that somewhere in the build, or in a plugin you use, the version to compile to is explicitly set to
1.5.x
v
Yes, because it's so weird. To ditch
buildSrc
and get rid of the warning:
Even if you do so, the reason for the warning probably persists, but is just not determined. If you only have the mixture at runtime rather than compiletime, it just "silently" fails with even more cryptic errors eventually.
f
1.5.1
is also not a Kotlin version Gradle ever used. This clearly shows that it has nothing to do with Gradle.
1
☝️ 1
m
If this violates Gradle's rules, it seems odd that it can't detect that. Gradle knows the dependency tree of every plugin, right? Is there a command to show plugin conflicts?
v
1.5.1
is also not a Kotlin version Gradle ever used. This clearly shows that it has nothing to do with Gradle.
I'm not so sure about that. 1.5.1 is not a Kotlin version at all. It also doesn't state so. It says "binary version of its metadata". This is probably the metadata version used in 1.5.10 or 1.5.20 or whatever.
1
f
@mikehearn is the code available anywhere? We are all speculating here and talking about 200 things at the same time. Would be much easier to pin point with access to the full thing.
m
I can probably upload the buildSrc directory specifically somewhere. There's nothing particularly sensitive about it I guess. Give me a second.
Or perhaps quicker, as it's a plugin related issue: https://gist.github.com/mikehearn/4c2a5ccfb3d222fa28805cf12b2c53e0
I tried disabling: dokka, power assert (which I already know wouldn't work), arrow analysis (which isn't used anyway). With those three disabled it still failed so the bad dependency must come from elsewhere.
Maybe a build scan shows the dependency tree of the buildSrc module. I'll try that.
f
Copy code
implementation("org.jetbrains.kotlin:kotlin-reflect:$kotlinVersion")
This line collides with
kotlin-dsl
.
Rest looks good. The plugins you include are also not very esoteric, I doubt that they are not built correctly against Gradle.
m
OK, let me try removing those three plugins and that line. I'm not sure why that's there tbh, I don't recall adding it and can't think of a reason why I'd have done so. Maybe it was in an earlier version of the template.
@Fleshgrinder Why is that wrong? It looks like it doesn't specify a version - isn't that the idea here, that you use the default version provided by Gradle?
f
I think someone added that line because of the warning printed by the Kotlin plugin where it states to add an explicit dependency on reflect. It's wrong because of https://github.com/bnorm/kotlin-power-assert/blob/master/build.gradle.kts#L2 where the version is specified and then inherited by ALL sub-projects.
m
OK - partial success! After removing that reflect line and the three plugins, I can get a build with Kotlin 1.7, woop! Thanks! Unfortunately, re-enabling Dokka and upgrading it to Dokka 1.7.0 brings back the same metadata version mismatch error as before.
🤔 1
f
It's actually not possible (without side effects) to have a Gradle multi-project with different Kotlin versions. No matter how Kotlin is applied. Again, afaik this has to do with the kotlinc compiler daemon and the build service it uses. The only way to have a Gradle multi-project with different Kotlin versions is through
includeBuild
. Which comes with it's own UX issues.
m
I see. Hmm. So that implies I can't upgrade past Kotlin 1.6 until Gradle does, because I'm using
buildSrc
which has to use Kotlin 1.5 or 1.6 and that's a normal "project", not a "composite build"?
f
I'm not certain on this one, as I said,
buildSrc
is special. @jendrik’s and @Vampire’s comments – who both know Gradle very well – suggest that it should work for
buildSrc
. Which, purely conceptually, makes sense, since it's a build executed in isolation before any other build. However, I haven't used
buildSrc
in a long while and cannot say for sure without creating a build with a
buildSrc
and running it.
m
Looks like the reflect line got added when Dokka was added to the project - unclear why but probably due to a warning, like you say.
v
A "composite build" is a build that includes other builds. Each of the builds is a full standalone multi-project build, just like
buildSrc
too. And if you build any build-logic to be used by Gradle, you have to stick to the Kotlin runtime embedded in the target Gradle version, whether you build it in
buildSrc
or in an included build doesn't matter.
👍 1
f
Well, he's clearly doing that, but the plugins he uses aren't. 😛 I cannot even find where the source is for the Dokka Gradle plugin. 🤔
v
Btw. all these problems is the major reason why I would never publish a Gradle plugin written in Groovy or Kotlin, but always only in Java and in the lowest version supported by the lowest version of Gradle I want to support.
👍 2
f
💯 agree for open source plugins.
v
Only that way you have the least compatibility problems like the ones you see here.
m
Right. The Dokka plugin seems to depend on the same version as Kotlin as the one it's designed for, which makes sense.
👍 1
e
j
I realised that I probably screwed up parts of the Kotlin sample myself two year ago or so. Did a PR for Gradle to fix that: https://github.com/gradle/gradle/pull/21145
👌 2
m
Thanks!
m
FWIW, Gradle 7.5 is out and is able to read the Kotlin 1.7 metadata. If you're stuck with 7.4-, you can always disable the check and it works in a lot of cases
Copy code
tasks.withType(org.jetbrains.kotlin.gradle.tasks.KotlinCompile::class.java) {
    kotlinOptions {
        freeCompilerArgs = freeCompilerArgs + "-Xskip-metadata-version-check"
    }
}
🌟 2
116 Views