Home > Software design >  Gradle multi-poject build api(project(..)) dependencies stoped working
Gradle multi-poject build api(project(..)) dependencies stoped working

Time:11-29

So I got this project in kotlin that consists of multiple sub projects. All of them are link with single settings.gradle file. It was all working fine until after a week of coding another part I noticed that i get a lot of compilation errors from one of the modules. So I started digging and found out that Intellij couldn't import classes from another sub project even though it is dependent on it via api project(':lib:content:model'). I couldn't figure out the reason why it stopped working and tried to build the project without intellij, just with graddlew. Then i got strange error:

command: ./gradlew :lib:game:model:build

FAILURE: Build failed with an exception.

* What went wrong:
Circular dependency between the following tasks:
:lib:game:model:classes
\--- :lib:game:model:compileJava
      --- :lib:game:model:compileKotlin
     |     --- :lib:game:model:jar
     |    |     --- :lib:game:model:classes (*)
     |    |     --- :lib:game:model:compileJava (*)
     |    |     --- :lib:game:model:compileKotlin (*)
     |    |    \--- :lib:game:model:kaptKotlin
     |    |          --- :lib:game:model:jar (*)
     |    |         \--- :lib:game:model:kaptGenerateStubsKotlin
     |    |              \--- :lib:game:model:jar (*)
     |    \--- :lib:game:model:kaptKotlin (*)
     \--- :lib:game:model:jar (*)

(*) - details omitted (listed previously)

I tried to google my way out of it but none of the suggestions from the internet worked for me. The strangest thing is that it USED to work when i was writing it previously. Then i just switched to another module and when i came back it was all like this, broken =(

I tried to isolate bugged code into test and ended up with lib module containing two sub modules content and game. Another one is project-types module where I store gradle plugins to overcome configuration duplication. content project just have one subproject called model and game project has three: api, impl, and also 'model`.

lib->game->model project depends on lib->content->model lib->game->impl project depends in lib->game->api

So another really strange thing is that lib->game->impl WORKD just fine and compiles even when he is dependent on lib->game->api. But the same thing doesn't work for 'lib->game->model' which uses THE SAME mechanism to depend on 'lib->content->model'

So I'm lost and don't know what to do. There is a good reason I need all of them to be different projects but I don't want to put myself through the hell of publishing new artifact to local repo every time I change code in one of them. Can someone please help me fix it T-T

My ./gradlew -q projects output:

------------------------------------------------------------
Root project 'test'
------------------------------------------------------------

Root project 'test'
\--- Project ':lib'
      --- Project ':lib:content'
     |    \--- Project ':lib:content:model'
     \--- Project ':lib:game'
           --- Project ':lib:game:api'
           --- Project ':lib:game:impl'
          \--- Project ':lib:game:model'

Included builds
\--- Included build ':project-types'

project-types contains common and kotlin-project sub projects.

common build.gradle:

plugins {
    id 'groovy-gradle-plugin'
}
repositories {
    mavenCentral()
}

and commons.gradle file inside src:

plugins {
    id 'java'
}

repositories {
    mavenCentral()
    mavenLocal()
}

dependencies {
    implementation 'com.fasterxml.jackson.core:jackson-core:2.13.4'
    implementation 'com.fasterxml.jackson.core:jackson-annotations:2.13.4'
    implementation 'com.fasterxml.jackson.core:jackson-databind:2.13.4'
    implementation 'com.fasterxml.jackson.datatype:jackson-datatype-jsr310:2.13.4'
    implementation 'com.fasterxml.jackson.module:jackson-module-paranamer:2.13.4'

    implementation 'org.slf4j:slf4j-api:1.7.36'
    implementation 'ch.qos.logback:logback-classic:1.2.11'

    implementation 'commons-io:commons-io:2.11.0'
    implementation 'org.apache.commons:commons-lang3:3.12.0'
    implementation 'commons-codec:commons-codec:1.15'
}

kotlin-project build.gradle file:

dependencyResolutionManagement {
    repositories {
        mavenLocal()
        mavenCentral()
        gradlePluginPortal()
        google()
    }
}

rootProject.name = 'project-types'

include 'commons'
include 'kotlin-project'

and it's kotlin-project.gradle file inside src:

plugins {
    id 'commons'
    id 'org.jetbrains.kotlin.jvm'
    id 'org.jetbrains.kotlin.kapt'
}

dependencies {
    implementation 'org.jetbrains.kotlin:kotlin-stdlib-jdk8'
    implementation 'org.jetbrains.kotlin:kotlin-reflect'
    implementation 'org.jetbrains.kotlinx:kotlinx-coroutines-jdk8:1.6.4'

    implementation 'com.fasterxml.jackson.module:jackson-module-kotlin'

    testImplementation 'org.junit.jupiter:junit-jupiter-api:5.9.1'
    testImplementation 'org.junit.jupiter:junit-jupiter-params:5.9.1'
    testImplementation 'org.mockito:mockito-junit-jupiter:4.8.1'
    testImplementation 'org.mockito.kotlin:mockito-kotlin:4.0.0'
    testRuntimeOnly 'org.junit.jupiter:junit-jupiter-engine:5.9.1'

}

test {
    useJUnitPlatform()
}

compileKotlin {
    kotlinOptions.jvmTarget = '17'
    kotlinOptions.freeCompilerArgs = ['-Xjsr305=strict', '-Xemit-jvm-type-annotations']
}

compileTestKotlin {
    kotlinOptions.jvmTarget = '17'
    kotlinOptions.freeCompilerArgs = ['-Xjsr305=strict', '-Xemit-jvm-type-annotations']
}

kapt {
    correctErrorTypes = true
}

So my main projects structure is:

My ./setting.gradle file content:

rootProject.name = 'test'

includeBuild 'project-types'

include 'lib:game'
include 'lib:game:model'
include 'lib:game:api'
include 'lib:game:impl'

include 'lib:content'
include 'lib:content:model'

./build.gradle file content

plugins {
    id 'org.jetbrains.kotlin.jvm' version "1.7.21" apply false
    id 'org.jetbrains.kotlin.kapt' version "1.7.21" apply false
}
repositories {
    mavenCentral()
}

./lib/content/model/build.gradle file content:

plugins {
    id 'kotlin-project'
}

group 'cvazer.test'
version '1.0.0'

dependencies {

}

./lib/game/api/build.gradle file content:

plugins {
    id 'kotlin-project'
}

group 'cvazer.test'
version '1.0.0'

dependencies {

}

./lib/game/impl/build.gradle file content:

plugins {
    id 'kotlin-project'
}

group 'cvazer.test'
version '1.0.0'

dependencies {
    api project(':lib:game:api')
}

./lib/game/model/build.gradle file content: (The one with the problem)

plugins {
    id 'kotlin-project'
}

group 'cvazer.test'
version '1.0.0'

dependencies {
    api project(':lib:content:model')
}

CodePudding user response:

Gradle has issues resolving dependencies when two subproject names are the same, even if the paths are different.

You have two subprojects, both called 'model'

  • :lib:game:model
  • :lib:content:model

Gradle can't distinguish between them.

I would recommend renaming your subprojects to flatter, without nesting, and making the names of each subproject unique.

└── lib/
    ├── game
    ├── game-model
    ├── game-api
    ├── game-impl
    ├── content
    └── content-model
  • Related