Gradle Multi-Project Builds TODEPLETE: Difference between revisions

From NovaOrdis Knowledge Base
Jump to navigation Jump to search
No edit summary
 
(51 intermediate revisions by the same user not shown)
Line 1: Line 1:
=DEPLETE TO=
{{Internal|Gradle Multi-Project Builds|Gradle Multi-Project Builds}}
=External=
=External=


Line 9: Line 11:


* [[Gradle_Project_and_Build_Script#Multi-Project_Builds|Gradle Project and Build Script]]
* [[Gradle_Project_and_Build_Script#Multi-Project_Builds|Gradle Project and Build Script]]
* [[Gradle_Settings_Script_and_Settings_Instance#Overview|settings.gradle]]


=Overview=
=Overview=
Line 14: Line 17:
A multi-project build is a build where more than one project is built during a single [[Gradle_Concepts#Execution|execution]] run. Multi-project builds are always represented by a tree of [[Gradle_Project_and_Build_Script#Overview|Project]] instances with a single root. Usually, there is a direct mapping between Project tree elements and directories on the file system where the project configuration and files are maintained, but this behavior is configurable.  
A multi-project build is a build where more than one project is built during a single [[Gradle_Concepts#Execution|execution]] run. Multi-project builds are always represented by a tree of [[Gradle_Project_and_Build_Script#Overview|Project]] instances with a single root. Usually, there is a direct mapping between Project tree elements and directories on the file system where the project configuration and files are maintained, but this behavior is configurable.  


<span id='Root_Project'></span>The [[Gradle_Settings_Script_and_Settings_Instance#Project_Hierarchy|project hierarchy]] is described in the [[Gradle_Settings_Script_and_Settings_Instance#Project_Hierarchy|settings.gradle]] file of the '''root project'''. This file is required for multi-project builds.
A project has a name, and a fully qualified path which uniquely identifies it in the hierarchy.


A project has a name, and a fully qualified path which uniquely identifies it in the hierarchy.
<span id='Root_Project'></span>The [[Gradle_Settings_Script_and_Settings_Instance#Project_Hierarchy|project hierarchy]] is described in the [[Gradle_Settings_Script_and_Settings_Instance#Project_Hierarchy|settings.gradle]] file of the '''root project'''. This file is required for multi-project builds. The root project build file can be used to configure as much commonality as possible in the [[Gradle_Project_and_Build_Script#allprojects.7B.7D|allprojects{...}]] block, leaving sub-projects to customize only what is specific for them.
 
<span id='Sub-Project'></span>A '''sub-project''' is a project that is part of a multi-project hierarchy, and it is not the [[#Root_Project|root project]]. There is a [[Gradle_Project_and_Build_Script#subprojects.7B.7D|subprojects{...}]] script block that can be used to provide configuration for sub-projects only. Sub-project may have their own [[Gradle_Settings_Script_and_Settings_Instance#Overview|settings.gradle]] and [[Gradle_Project_and_Build_Script#Overview|build.gradle]] configuration files, though they are not required: the behavior of sub-project can be configured in the root project's configuration files.
 
{{Note|It is considered good practice to break configuration into multiple build.gradle files, each sub-project with its own build file maintaining sub-project-specific configuration, while the root project build contains shared configurations.}}


The [[#Project_Root|root project]] build file can be used to configure as much commonality as possible in the [[Gradle_Project_and_Build_Script#allprojects.7B.7D|allprojects{...}]] block, leaving sub-projects to customize only what is specific for them. There is a [[Gradle_Project_and_Build_Script#subprojects.7B.7D|subprojects{...}]] block that can be used to provide configuration for sub-projects only. Child directories may have their own [[Gradle_Settings_Script_and_Settings_Instance#Overview|settings.gradle]] and [[Gradle_Project_and_Build_Script#Overview|build.gradle]] configuration files.
Note that declaring a sub-project does not necessarily mean that anything will be built in that sub-project. A [[Gradle_Project_and_Build_Script#Overview|build.gradle]] with the appropriate plugins - which in turn contribute the necessary tasks - must also be added to the sub-project. Alternatively, the plugins may be applied in the root project's build.gradle with [[Gradle_Project_and_Build_Script#allprojects.7B.7D|allprojects{...}]] or [[Gradle_Project_and_Build_Script#subprojects.7B.7D|subprojects{...}]]. A build.gradle file is not necessary if the appropriate plugins are applied to subprojects from root.


The structure of a hierarchical project can be displayed with:
The component project and the associated structure of a multi-project build can be displayed with:


  [[Gradle_Operations#projects|gradle projects]]
  [[Gradle_Operations#projects|gradle projects]]


=Sub-Project=
It is possible to run any [[Gradle_Task#Overview|task]] in any sub-project with the following syntax:


=<span id='Dependencies_Between_Subprojects'></span>Inter-Project Dependencies=
  gradle :<''sub-project-path''>:<''task-name''>


Sub-projects do not automatically expose their artifacts to other sub-projects of the same multi-build project. The dependencies between sub-projects must be declared explicitly in the [[Gradle_Project_and_Build_Script#dependencies.7B.7D|dependencies{...}]] script block of the dependent sub-project. For example, if classes that belong to "subproject-B" depend on classes in "subproject-A", then subproject-B build.gradle must contain:
If you were to spend a lot of time working in one sub-project, changing to that directory and running the build from there is normal. Running a task from that subdirectory will trigger all necessary actions form its dependency projects, thanks to the Gradle task graph implementation.


<syntaxhighlight lang='groovy'>
=Multi-Projecte Build Layout=
dependencies {
    ...
    implementation project(':subproject-A')
    ...
}
</syntaxhighlight>


=Multi-Project Build Layout=
A multi-project build can have a flat or hierarchical layout.


[[Gradle_Settings_Script_and_Settings_Instance#Project_Hierarchy|Project Hierarchy]]
==<span id='Hierarchical'>Hierarchical Layout==


=To Deplete=
A hierarchical layout allows for multiple level of projects. The path of a sub-project relative to the root project is assumed to match the relative file system path of the directory hosting the sub-project. For example, a ":sub-project1:child2" sub-project is mapped onto a "./sub-project1/child2" directory, relative to the root directory of the project. "project1:child2:sub-child3" implies three projects: "project1", "project1:child2" and "project1:child2:sub-child3". A hierarchical layout is specified by the [[Gradle_Settings_Script_and_Settings_Instance#include|include(...)]] method of the Settings object, invoked in the settings.gradle configuration file.


==<span id='Flat'>Flat Layout==


A flat layout is  is specified by the [[Gradle_Settings_Script_and_Settings_Instance#includeFlat|includeFlat(...)]] method, which takes directory names are argument. These directories need to exist as siblings of the root project directory.


=Inter-Project "Communication"=


See: {{Internal|Gradle_Programming#Inter-Project_.22Communication.22|Gradle Programming - Inter-Project "Communication"}}


=<span id='Dependencies_Between_Subprojects'></span>Inter-Project Dependencies=


Sub-projects do not automatically expose their artifacts to other sub-projects of the same multi-build project. The dependencies between sub-projects must be declared explicitly in the [[Gradle_Project_and_Build_Script#dependencies.7B.7D|dependencies{...}]] script block of the dependent sub-project. For example, if classes that belong to "subproject-B" depend on classes in "subproject-A", then subproject-B build.gradle must contain:


<syntaxhighlight lang='groovy'>
dependencies {
    ...
    implementation project(':subproject-A')
    ...
}
</syntaxhighlight>


It is possible to run any task in any subproject with the following syntax:
{{Warn|The dependent sub-project must apply the Java plugin, otherwise the "implementation" [[Gradle_Dependencies_and_Dependency_Configurations#Dependency_Configuration|dependency configuration]] is not available, and the build fails. If the dependent project does not need the [[Gradle_Java_Plugin#Overview|Java plugin]], then it must use a configuration exposed by one of its plugins.}}


  gradle :<''subproject-name''>:<''task-name''>
More details: {{Internal|Gradle_Dependencies_and_Dependency_Configurations#Dependencies_between_Sub-Projects|Dependencies between Sub-Projects}}


If you were to spend a lot of time working in one sub-project, changing to that directory and running the build from there is normal. Running a task from that subdirectory will trigger all necessary actions form its dependency projects, thanks to the Gradle task graph implementation.
=<span id='Project_Filtering'></span>Selective Project Configuration=
 
====Project Filtering====


{{External|https://docs.gradle.org/4.7/userguide/multi_project_builds.html#sub:project_filtering}}
{{External|https://docs.gradle.org/4.7/userguide/multi_project_builds.html#sub:project_filtering}}


Sub-projects to apply specific configuration to can be selected dynamically with an expression. <tt>configure</tt> can be used with a predicate closure to allow for selective sub-projects to be configured.
Selective project configuration can be achieved via project filtering, by invoking Project's [https://docs.gradle.org/current/dsl/org.gradle.api.Project.html#org.gradle.api.Project:configure(java.lang.Iterable,%20groovy.lang.Closure) configure(...)] method with a predicate closure that selects specific sub-projects, in the root project's build.gradle, as shown in the example below. The method is executed in the [[Gradle_Concepts#Configuration|configuration phase]], in the order in which it was specified in build.gradle: if other script blocks are declared under the [https://docs.gradle.org/current/dsl/org.gradle.api.Project.html#org.gradle.api.Project:configure(java.lang.Iterable,%20groovy.lang.Closure) configure(...)] method invocation, they will be executed after it, possibly overwriting configuration introduced by [https://docs.gradle.org/current/dsl/org.gradle.api.Project.html#org.gradle.api.Project:configure(java.lang.Iterable,%20groovy.lang.Closure) configure(...)].


<syntaxhighlight lang='groovy'>
<syntaxhighlight lang='groovy'>
configure(subprojects.findAll {it.name == 'subproject-A' || it.name == 'subproject-A'} ) {  
configure(subprojects.findAll {it.name == 'subproject-A' || it.name == 'subproject-B'} ) {  
 
    println "configuring sub-project $it"


     apply plugin : ...
     apply plugin : ...
Line 74: Line 88:
</syntaxhighlight>
</syntaxhighlight>


====Layout====
===allprojects===
 
All projects in a multi-project build can be configured by code place in the closure applied by [[Gradle_Project_and_Build_Script#allprojects.7B.7D|allprojects{...}]]:
 
<syntaxhighlight lang='groovy'>
allprojects {


=====<span id='Hierarchical'></span>Hierarchical=====
    println 'this configuration applies to all projects of a multi-project build'
    ...
}
</syntaxhighlight>


The project path is assumed to be equal to the relative physical file system path. [[Settings.gradle#Overview|"include" method]] argument "project1:child2" is mapped onto a "project1/child2" directory, relative to the root directory of the project. "project1:child2:subchild3" implies three projects: "project1", "project1:child2" and "project1:child2:subchild3".
===subprojects===


=====<span id='Flat'></span>Flat=====
Sub-projects of a multi-project build can be configured by code place in the closure applied by [[Gradle_Project_and_Build_Script#subprojects.7B.7D|subprojects{...}]]:


A flat layout is introduced by the [[settings.gradle#Overview|"includeFlat" method]], which takes directory names are argument. These directories need to exist as samplings of the root project directory.
<syntaxhighlight lang='groovy'>
subprojects {
 
    println 'this configuration applies to all sub-projects of a multi-project build'
    ...
}
</syntaxhighlight>

Latest revision as of 23:59, 3 October 2020

DEPLETE TO

Gradle Multi-Project Builds

External

Internal

Overview

A multi-project build is a build where more than one project is built during a single execution run. Multi-project builds are always represented by a tree of Project instances with a single root. Usually, there is a direct mapping between Project tree elements and directories on the file system where the project configuration and files are maintained, but this behavior is configurable.

A project has a name, and a fully qualified path which uniquely identifies it in the hierarchy.

The project hierarchy is described in the settings.gradle file of the root project. This file is required for multi-project builds. The root project build file can be used to configure as much commonality as possible in the allprojects{...} block, leaving sub-projects to customize only what is specific for them.

A sub-project is a project that is part of a multi-project hierarchy, and it is not the root project. There is a subprojects{...} script block that can be used to provide configuration for sub-projects only. Sub-project may have their own settings.gradle and build.gradle configuration files, though they are not required: the behavior of sub-project can be configured in the root project's configuration files.


It is considered good practice to break configuration into multiple build.gradle files, each sub-project with its own build file maintaining sub-project-specific configuration, while the root project build contains shared configurations.

Note that declaring a sub-project does not necessarily mean that anything will be built in that sub-project. A build.gradle with the appropriate plugins - which in turn contribute the necessary tasks - must also be added to the sub-project. Alternatively, the plugins may be applied in the root project's build.gradle with allprojects{...} or subprojects{...}. A build.gradle file is not necessary if the appropriate plugins are applied to subprojects from root.

The component project and the associated structure of a multi-project build can be displayed with:

gradle projects

It is possible to run any task in any sub-project with the following syntax:

 gradle :<sub-project-path>:<task-name>

If you were to spend a lot of time working in one sub-project, changing to that directory and running the build from there is normal. Running a task from that subdirectory will trigger all necessary actions form its dependency projects, thanks to the Gradle task graph implementation.

Multi-Projecte Build Layout

A multi-project build can have a flat or hierarchical layout.

Hierarchical Layout

A hierarchical layout allows for multiple level of projects. The path of a sub-project relative to the root project is assumed to match the relative file system path of the directory hosting the sub-project. For example, a ":sub-project1:child2" sub-project is mapped onto a "./sub-project1/child2" directory, relative to the root directory of the project. "project1:child2:sub-child3" implies three projects: "project1", "project1:child2" and "project1:child2:sub-child3". A hierarchical layout is specified by the include(...) method of the Settings object, invoked in the settings.gradle configuration file.

Flat Layout

A flat layout is is specified by the includeFlat(...) method, which takes directory names are argument. These directories need to exist as siblings of the root project directory.

Inter-Project "Communication"

See:

Gradle Programming - Inter-Project "Communication"

Inter-Project Dependencies

Sub-projects do not automatically expose their artifacts to other sub-projects of the same multi-build project. The dependencies between sub-projects must be declared explicitly in the dependencies{...} script block of the dependent sub-project. For example, if classes that belong to "subproject-B" depend on classes in "subproject-A", then subproject-B build.gradle must contain:

dependencies {
    ...
    implementation project(':subproject-A')
    ...
}

The dependent sub-project must apply the Java plugin, otherwise the "implementation" dependency configuration is not available, and the build fails. If the dependent project does not need the Java plugin, then it must use a configuration exposed by one of its plugins.

More details:

Dependencies between Sub-Projects

Selective Project Configuration

https://docs.gradle.org/4.7/userguide/multi_project_builds.html#sub:project_filtering

Selective project configuration can be achieved via project filtering, by invoking Project's configure(...) method with a predicate closure that selects specific sub-projects, in the root project's build.gradle, as shown in the example below. The method is executed in the configuration phase, in the order in which it was specified in build.gradle: if other script blocks are declared under the configure(...) method invocation, they will be executed after it, possibly overwriting configuration introduced by configure(...).

configure(subprojects.findAll {it.name == 'subproject-A' || it.name == 'subproject-B'} ) { 

    println "configuring sub-project $it"

    apply plugin : ...

    dependencies {
        ...
    }
}

allprojects

All projects in a multi-project build can be configured by code place in the closure applied by allprojects{...}:

allprojects {

    println 'this configuration applies to all projects of a multi-project build'
    ...
}

subprojects

Sub-projects of a multi-project build can be configured by code place in the closure applied by subprojects{...}:

subprojects {

    println 'this configuration applies to all sub-projects of a multi-project build'
    ...
}