Multiproject, multiconfiguration build

I’m working on migration of a large project (with 40+ subprojects) from ANT to Gradle.
I am wondering what would be the best build strategy to adopt.
Each project has a layout like:

    - src1
    - src2
    - src3
    - ...
    - lib1
    - lib2
    - lib3
    - ...

All these projects will compose a large final artifact that has folders lib1, lib2 etc (of all subprojects), some jars built by src1, src2 etc (of all subprojects).

These libs folders in final artifact have a classloader hierarchy (let’s say, lib1 is parent of lib2, lib2 is parent of lib3 and so on).

So far, we have declared the libs folders as configurations (in every project). Each configuration extendsFrom the accordingly configuration (in this example, lib2.extendsFrom(lib1), lib3.extendsFrom(lib2) and so on).

Question: What’s the best way of declaring dependencies so the dependency configuration will work well?
Just to be clear, let’s say the following dependencies are resolved:

- project 1
    - lib1
        - dependency A, version 1
        - dependency B, version 1
    - lib2
        - dependency C, version 1
            - dependency A, version 2
- project 2
    - lib1
        - dependency C, version 2
            - dependency A, version 3
    - lib2
        - dependency B, version 2

In this scenario, I would expect the resolution would be as follows:

  1. lib1 < A1 (from project 1), B1 (from project 1), C2 (from project 2)
  2. lib1: A1 -> A3 (since C2 depends on A3), so, lib1 = A3, B1, C2
  3. lib2 < C1 (from project 1), B2 (from project 2)
  4. lib2: C1: removed (since it is already in lib1 and lib2.extendsFrom(lib1))
  5. lib2: B2 goes to lib1

In the end, would be: lib1 = A3, B2, C2; lib2 = nothing.


The way we did it was we split up our source folders so that each one sat in a different subproject.


Then, in the build.gradle files, when project 1 was a dependency for 2 and 4, and 3 was a dependency of 4, we declared

project2 build.gradle

dependencies {
    compile project(':project1')

project4 build.gradle

dependencies {
    compile project(':project1')
    compile project(':project3')

The goal was to have 1 artifact for each chunk of code, and have them logically be separated.