Search code examples
gradlegradle-kotlin-dsl

Gradle Kotlin DSL: Problems with subprojects and plugins


Gradle 6.1.1

I have been trying to convert my projects' gradle files using Kotlin DSL but so far failed. All my projects are multi-project builds in Java. I followed the plugin subproject examples here

It looks like that:

plugins {
    idea
    eclipse
}

subprojects {
    apply(plugin = "java")

    dependencies {
       implementation("com.google.guava:guava:28.1-jre")
       //...
    }
}

The java plugin does not seem to be understood in the subprojects and all the 'implementation' lines get an unresolved reference.


Solution

  • See documentation here https://docs.gradle.org/current/userguide/kotlin_dsl.html.

    Type-safe accessors are unavailable for model elements contributed by the following:

    • Plugins applied via the apply(plugin = "id") method
    • ...
     implementation()
    

    Is such a typesafe accessor. The non-typesafe way looks like this:

        apply(plugin = "java-library")
        dependencies {
            "api"("javax.measure:unit-api:1.0")
            "implementation"("tec.units:unit-ri:1.0.3")
        }
    

    With the groovy DSL, all method are resolved dynamically (not typesafe), so there it does not matter.

    It helps to understand that build.gradle.kts files are not pure kotlin files. They would look much uglier with plenty of imports at the top. So the gradle runtime treats the "buildscript" and the "plugins" block special. "plugins" is transformed into import statements. That does not work with the apply() method, which is run later when the file was compiled. That's also why the plugins block cannot be used in other places, it is a special construct that just pretends to be a normal code block. A little more detail here https://docs.gradle.org/current/dsl/org.gradle.plugin.use.PluginDependenciesSpec.html

    Advice

    Just from a module design perspective, I would generally recommend that the root module in a multi module build remains agnostic of what the submodules do, even if there are many people using the subprojects block as your example does. Let each submodule's build file be as complete as if it was an independent gradle project, so readers don't have to read 2 files to get the full picture.

    There are better explicit ways to share configuration between subprojects.

    The subprojects block in the root file is best used to add additional tasks if they are needed from the root of the project, IMO. Not to inject plugins or configuration.