Gradle build: how to set up a multilevel project (3+ levels)?

1.7k views Asked by At

I am having troubles with seting up 3 level gradle multi-project:

Level_1_Proj
│
├── Level_2_Proj_A
│   │ 
│   ├── Level_3_Proj_C
│   └── Level_3_Proj_D
│
└── Level_2_Proj_B
    │
    ├── Level_3_Proj_E
    └── Level_3_Proj_F

I would like to be able to:

  1. set up dependencies between projects of the same level in the build script, like:
 dependencies {
     project('Level_2_Proj_A') {
         dependencies {
             implementation project('Level_2_Proj_B')
         }
     }
 }
  1. also want to be able to build (the subtree) starting the bash command [$gradle build] at any level [then build down the projects' subtree]

I have achieved building from the middle and bottom levels, but I cannot setup the build from the top level. Getting error:

A problem occurred evaluating project ‘Level_2_Proj_A’. Project with path ‘Level_3_Proj_C’ could not be found in project ‘Level_2_Proj_A’.

Is it possible? If so, how to configure? Thanks

1

There are 1 answers

4
afterburner On

Alright, here's how I managed to get it working. Given the following directory structure:

.
├── A
│   ├── C
│   │   └── build.gradle.kts
│   ├── D
│   │   └── build.gradle.kts
│   └── build.gradle.kts
├── B
│   ├── E
│   │   └── build.gradle.kts
│   ├── F
│   │   └── build.gradle.kts
│   └── build.gradle.kts
├── build.gradle.kts
├── gradle
│   └── wrapper
│       ├── gradle-wrapper.jar
│       └── gradle-wrapper.properties
├── gradlew
├── gradlew.bat
└── settings.gradle.kts

The settings.gradle.kts has the following content:

rootProject.name = "multi-module-build"

include(":A")
include(":A:C")
include(":A:D")
include(":B")
include(":B:E")
include(":B:F")

Each build.gradle.kts has a call task that prints the name path of the project, e.g. Inside the C project:

tasks.register("call") {
    println(":A:C")
}

Inside the A project:

tasks.register("call") {
    dependsOn(":A:C:call")
    dependsOn(":A:D:call")
    println(":A")
}

tasks["build"].dependsOn(":A:call")

The tasks["build"].dependsOn(":A:call") tells Gradle to invoke :A:call when building. The two dependsOn inside the call definition for A invoke the subproject call tasks.

There is a similar structure available for B.

When running gradle build at root level, this is the output I get:

:A
:B
:A:C
:A:D
:B:E
:B:F

When running gradle build inside the A subproject, I get:

:A
:A:C
:A:D

When running it inside :A:C, I don't get any output because I haven't specified that C's build task should depend on call, but that could easily be done. Let me know if this doesn't work for you. I've used the Kotlin DSL for gradle, but you're perfectly free to change it to the Groovy variant.