Skip to content

Creating and Managing Multi-Build Projects

Estimated time to read: 3 minutes

Overview

Applications that consist of multiple projects, each project will have it's own build file Specify a top level build file to configure projects and set dependencies Specify a top level settings file to specify projects Project level build files, these set project level properties and tasks

Multi-Project Builds

Demo File Structure

Example file structure for the demo throughout this module.

- jacket
 - build.gradle
 - settings.gradle
 - Repository
  - src
  - build.gradle
 - JacketService //Depends on Repository
  - src
  - build.gradle

settings.gradle

Groovy/Kotlin
include 'Repository', 'JacketService' //Include both sub-project folders into our multi-build project

build.gradle

Here, we can add properties to the file that affect all of the projects and we can add project specific settings to the file.

Groovy
allprojects { //Applies to all projects within the build file
 plugins { 
  id 'java'
 }
}

version = '1.0-SNAPSHOT' //Set the version string for all of the projects

project(':Repository') { //Project specific settings syntax

}

project(':JacketService') {
 dependencies {
  implementation project(':Repository') // JacketService is dependent on the Repository project
 }
}

build.gradle.kts

Kotlin
allprojects { //Applies to all projects within the build file
 apply(plugin="java")
 version = '1.0-SNAPSHOT' //Set the version string for all of the projects
}

project(':Repository') { //Project specific settings syntax

}

project(':JacketService') {
 dependencies {
  implementation project(':Repository') // JacketService is dependent on the Repository project
 }
}

The above build files will first build the Repository project, as JacketService is dependant on it, then build the JacketService.

Top-level variable inheritance

Version variables can be defined in the top-level build file. These variables are then also accessible from any sub-project build files that are called by the top-level build file.

allprojects

The allprojects element affects all projects within the build file including the top-level.

Groovy
allprojects { //Applies to all projects within the build file
 plugins { 
  id 'java'
 }
 version = '1.0-SNAPSHOT' //Set the version string for all of the projects

}

subprojects

The subprojects element, conversely to the allprojects element, only affects sub-projects, it does not affect the top-level.

Groovy
subprojects {
 apply plugin: 'java'
 version = '0.1-SNAPSHOT'

 repositories {
  jcenter()
 }
}

Kotlin quirks

When using a build file based on the Kotlin DSL, it is worth noting that any variables that have been specified at the top of the file, or in settings.gradle, have to be redeclared when used within an allprojects or subprojects block.

Kotlin
val h2_version: String by project

allprojects { //Applies to all projects within the build file
 apply(plugin="java")
 version = '1.0-SNAPSHOT' //Set the version string for all of the projects
}

subproject {
 dependencies {
  val h2_version: String by project
  classpath("com.h2database:h2:$h2_version")
 }
}
project(':Repository') { //Project specific settings syntax
}

Using the java-library plugin

Example Top-level build.gradle

Groovy
plugins {
 id 'java'
}

subprojects {
 repositories {
  jcenter()
 }
}

version = '0.1-SNAPSHOT'

project(':jCurlLib'){
 dependencies {

 }
}

project(':TerminalClient') {
 apply plugin: 'java'
 dependencies {
  implementation project(':jCurlLib')
 }
}

Example jCurlLib build.gradle

Groovy
apply plugin: 'java-library'

dependencies {
 implementation 'org.apache.httpcomponentsLhttpcore:4.4.13'
}

Example TerminalClient build.gradle

Groovy
apply plugin: 'application'

version = '1.0-SNAPSHOT'

Explanation

In the example above, jCurlLib is using the java-library plugin.

There is a client class within jCurlLib's code. The important part of this class is its' return value. It returns type StatusLine. which is a part of the Apache HttpCore library.

StatusLine is called within TerminalClient's code through the use of a instantiated object, however, TerminalClient's code is unaware of StatusLine as a type.

This can be fixed by adding a dependency section within the TerminalClient build file. However, this is not good practise. Instead, we edit the jCurlLib build.gradle file and change implementation to api. This tells Gradle to do everything that implementation does, plus expose this to everything that jCurlLib interacts with; in this instance, TerminalClient.

Example Updated jCurlLib build.gradle

Groovy
apply plugin: 'java-library'

dependencies {
 api 'org.apache.httpcomponentsLhttpcore:4.4.13'
}