Multiproject builds in Gradle

Gradle is a beast!

Having a background in simpler build systems like Makefile and Ant, Gradles DSL confused me initially.

Gradle has sections that basically are lambdas. Code sections that are called by Gradle at specific times in the build.

It can sometimes be hard to see the underlying structure.

A good way of starting a complicated multi project build is to use the gradle wizard: gradle init

Select 2 (application) 3 (Java) and 2 (application and library)

peter@nitro:~/dev/slask2$ gradle init

Select type of project to generate:
1: basic
2: application
3: library
4: Gradle plugin
Enter selection (default: basic) [1..4] 2

Select implementation language:
1: C++
2: Groovy
3: Java
4: Kotlin
5: Scala
6: Swift
Enter selection (default: Java) [1..6] 3

Split functionality across multiple subprojects?:
1: no - only one application project
2: yes - application and library projects
Enter selection (default: no - only one application project) [1..2] 2

Select build script DSL:
1: Groovy
2: Kotlin
Enter selection (default: Groovy) [1..2] 1

Project name (default: slask2):
Source package (default: slask2):

> Task :init
Get more help with your project: https://docs.gradle.org/7.2/
samples/sample_building_java_applications_multi_project.html

BUILD SUCCESSFUL in 23s
2 actionable tasks: 2 executed

Now look in the root settings.gradle (most important) and build.gradle (not so important) and you will see the structure.

Directory overview

    ├── myapp
    │   ├── bin
    │   ├── build
    │   └── src
    │       ├── main
    │       │   ├── java
    │       │   │   └── mementomori
    │       │   │       └── app
    │       │   └── resources
    │       └── test
    │           ├── java
    │           │   └── mementomori
    │           │       └── app
    │           └── resources
    ├── buildSrc
    │   └── src
    │       └── main
    │           └── groovy
    ├── gradle
    │   └── wrapper
    ├── mylib
    │   ├── bin
    │   ├── build
    │   ├── libs
    │   ├── resources
    │   └── src
    │       └── main
    │           ├── java
    │           │   └── se
    │           │       └── fsh
    │           │           ├── ib
    │           │           └── tools
    │           └── resources
    

The graph shows a setup with an app (myapp) and a library (mylib)

Settings.gradle

On the top-level, you have a file settings.gradle with the following content:

settings.gradle will import the submodules in a statement like this:

rootProject.name = 'myproject'
include('myapp', 'mylib')

And in subdirectories ./myapp, ./mylib are the respective submodules.

The build.gradle for the individual subprojects are similar top single project builds, with a few differences.

Plugin system

Setting up the plugins in the subprojects is very important.

plugins {
    id 'mementomori.java-library-conventions'
    id 'java-library'
}

The plugin ‘mementomori.java-library-conventions’ needs some explanation.

This plugin is located in the buildSrc/src/main/groovy folder
which contains three plugins

  • The “java-common-conventions” plugin
  • The “java-applications-conventions” plugin
  • The “java-library-conventions” plugin
  • The names are self-explanatory. Both the “application” and “library” plugin
    references the “common plugin”.

    So the “common” plugin for example have this statement:

    repositories {
        // Use Maven Central for resolving dependencies.
        mavenCentral()
    }
    

    And since the application-conventions and library-conventions both reference this common plugin,
    they won’t have to specify it themselves.

    So use these three plugins for stuff that all applications and libraries should have,
    and then you won’t have to bother with including them in the app/lib’s own build.gradle.

    The apps build.gradle for example, contains:

    plugins {
        id 'mementomori.java-application-conventions'
        id 'java'
    }
    

    The same applies for dependencies, tasks and everythin else you can write in your build file.

    So when you add subprojects/submodules, you add a parallel directory to app/mylib, make sure to include it in settings.gradle, setup a new build.gradle for the subproject and off you go!

    Leave a Reply

    Your email address will not be published. Required fields are marked *

    This site uses Akismet to reduce spam. Learn how your comment data is processed.