Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Confusion and issues with mixing Groovy/Kotlin versions in Gradle builds #17375

Open
eskatos opened this issue Jun 8, 2021 · 3 comments
Open
Labels
a:investigation Issues requiring decision or investigation @core Issue owned by GBT Core in:groovy-dsl in:kotlin-dsl in:plugin-development

Comments

@eskatos
Copy link
Member

eskatos commented Jun 8, 2021

There's friction and confusion in the community of build and plugin authors about how to mix Groovy/Kotlin versions in Gradle builds. This can be seen in the many open issues on several issue tracker about this, see below. This issue describes the current status quo and aims at starting an open discussion about this problem to find acceptable solutions.


Gradle provides a runtime environment for plugins. This runtime environment includes both Groovy and Kotlin runtimes.

The respective embedded versions can be seen in the output of gradle --version. Below are the versions reported for a bunch of Gradle versions:

Gradle Groovy Kotlin
4.10.3 2.4.15 1.2.61
5.0 2.5.4 1.3.10
5.6.4 2.5.4 1.3.41
6.0 2.5.8 1.3.50
6.9 2.5.12 1.4.20
7.0 3.0.7 1.4.31

Note that Gradle 6.9 embeds Kotlin 1.4 but it is set up to use the Kotlin language level and api version 1.3 to compile build scripts for backwards compatibility reasons. Gradle 7.0 then enables Kotlin language level and api version 1.4.

Gradle plugins (build scripts, local plugins, external plugins) are executed against the Gradle runtime. Any dependency resolution that happens to resolve external plugins sits on top of the Gradle runtime. The consequence of this is that all plugins used in a build must be compatible with the Gradle runtime.

If a plugin wants to use language features of a more recent version of Groovy or Kotlin, or, a library compiled against a more recent version of Groovy or Kotlin, then it can only do so in a context that is isolated from the Gradle runtime. For example it can use the Worker API with classloader or process isolation.

That's basically how the core groovy plugin allows one to compile Groovy sources and run Groovy tests with a more recent version of Groovy than the one embedded in the Gradle runtime.

The Kotlin plugin didn't comply with this constraint of the Gradle runtime until 1.5.10. Before that it depended on the kotlin-stdlib of the target Kotlin version instead of depending on a version that is compatible with the target Gradle version. This is fixed starting with 1.5.10. This should make the situation much simpler going forward. See KT-41142.

On top of this constraint there're builds where one can use Groovy or Kotlin to build custom local plugins. This is done using either buildSrc or included builds. In such cases, the local plugins must comply with the Gradle runtime, thus those builds must use a Groovy/Kotlin version compatible with the used Gradle version to build those plugins. As explained above, they can use a different Groovy/Kotlin version to build the actual project sources though.

Another use case that should be addressed is authoring plugins that target multiple Gradle versions, using different embedded Groovy/Kotlin versions. The simplest course is to use a Groovy/Kotlin version that is compatible with all targeted Gradle versions, most probably the lowest one. Publishing different variants of a plugin might be a way to leverage more recent versions of Groovy/Kotlin for more recent versions of Gradle.

Some causes of the confusion

Here are two known causes for the confusion, not an exhaustive list:

  1. Lack of knowledge of the constraints described above.
    This is most probably a lack of clarity in how this is documented.
    Information about this is scattered across the Gradle user manual making it hard to learn and grasp.

  2. Error/warning messages in case of conflicts not helpful if not misleading.
    Again, if this is the case those messages should be reworked to be more helpful.

Related issues

Related gradle/gradle issues

Related Kotlin issues

@eskatos eskatos added the @core Issue owned by GBT Core label Jun 8, 2021
@eskatos
Copy link
Member Author

eskatos commented Jun 8, 2021

💡 The plugin development plugin could warn/fail if the plugin's runtime dependencies include modules that are provided by the Gradle runtime. This would help prevent issues at an early phase of plugin development.

@eygraber
Copy link
Contributor

eygraber commented Jun 11, 2021

I think this clarifies a lot of what I've been piecing together by myself, so thank you for putting it together!

EDIT: I think I managed to untangle my issue and was able to resolve it (see #16345 (comment)).

However, I'm still not entirely how to resolve this for my use case.

I have a buildSrc that contains precompiled script plugins that I use to configure the Kotlin and AGP plugins uniformly for all of my project modules (essentially replacing subprojects in my root build.gradle.kts).

My buildSrc/build.gradle.kts looks like:

plugins {
  `kotlin-dsl`
}

repositories {
  mavenCentral()
  google()
}

dependencies {
  compileOnly(gradleApi())

  implementation("com.android.tools.build:gradle:7.0.0-beta03")
  implementation(kotlin("gradle-plugin", "1.5.10"))
}

My precompiled script plugin looks like this:

plugins {
  id("kotlin-android")
}

tasks.withType<KotlinJvmCompile>().configureEach {
  kotlinOptions {
    jvmTarget = "11"

    allWarningsAsErrors = true
  }
}

dependencies { ... }

And finally my project build.gradle.kts files looks like:

plugins {
  `my-precompiled-plugin`
}

If I don't add implementation(kotlin("gradle-plugin", "1.5.10")) in buildSrc/build.gradle.kts then I get an error saying that the kotlin-android plugin was not found. If I do add it, I get the warning about multiple versions of Kotlin on the classpath.

AlgirdasPundzius pushed a commit to ProtonMail/protoncore_android that referenced this issue Sep 13, 2021
Gradle plugins written in Kotlin are recommended to use gradle embedded kotlin runtine. For more info about this check gradle/gradle#16345 and gradle/gradle#17375. Using embeddedKotlinVersion we automatically set the correct kotlin version for our plugins based on the gradle version we are currently using.
@stale
Copy link

stale bot commented Jun 19, 2022

This issue has been automatically marked as stale because it has not had recent activity. Given the limited bandwidth of the team, it will be automatically closed if no further activity occurs. If you're interested in how we try to keep the backlog in a healthy state, please read our blog post on how we refine our backlog. If you feel this is something you could contribute, please have a look at our Contributor Guide. Thank you for your contribution.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
a:investigation Issues requiring decision or investigation @core Issue owned by GBT Core in:groovy-dsl in:kotlin-dsl in:plugin-development
Projects
None yet
Development

No branches or pull requests

3 participants