2

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 Answers1

2

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.

afterburner
  • 2,552
  • 13
  • 21
  • As you can notice I want to be able to build the project subtree from any node (subproject). It is easy and standard configuration(settings file) if you have only the two levels (L2 & L3). The question is how to configure the top level (L1) project .... to run the build down the tree. I have tried some gradle.settings configurations like "include Level2_ProjA , include Level2_ProjA:Level3_ProjC" etc configurations Any ideas? – Talavera316 Mar 25 '20 at 23:45
  • Hi Dragos, thanks a lot for your neat and precise answer. I will try to use it. BTW. There are interesting forum discussions about Gradle inability of recursion build (what is available in maven) – Talavera316 Mar 27 '20 at 14:25
  • I have yet to encounter something Maven can do that you couldn't do in Gradle as well. Admittedly, Gradle may lack some of the concepts and it may be a bit more involved, but it should be achievable. Including recursive builds. Though I am unsure as to the benefits you would get from recursively nesting subprojects. – afterburner Mar 27 '20 at 14:28
  • Doesn't seem ideal because every target.. "call", "bootWar", "clean"...whatever has to be setup in sub-build.gradle... whereas for a single level multi-project, gradle seems smart enough to deal with that for any target you might choose. Still... I don't have a better answer. – xpusostomos Feb 07 '22 at 00:47