// Copyright (C) 2023 Gradle, Inc.
//
// Licensed under the Creative Commons Attribution-Noncommercial-ShareAlike 4.0 International License.;
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//      https://creativecommons.org/licenses/by-nc-sa/4.0/
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

[[intro_multi_project_builds]]
= Multi-Project Build Basics

Gradle supports multi-project builds.

image::gradle-basic-9.png[]

While some small projects and monolithic applications may contain a single build file and source tree, it is often more common for a project to have been split into smaller, interdependent modules.
The word "interdependent" is vital, as you typically want to link the many modules together through a single build.

Gradle supports this scenario through _multi-project_ builds.
This is sometimes referred to as a multi-module project.
Gradle refers to modules as subprojects.

A multi-project build consists of one root project and one or more subprojects.

[[sec:project_structure]]
== Multi-Project structure

The following represents the structure of a multi-project build that contains two subprojects:

image::multi-project-structure.png[]

The directory structure should look as follows:

----
├── .gradle
│   └── ⋮
├── gradle
│   ├── libs.version.toml
│   └── wrapper
├── gradlew
├── gradlew.bat
├── settings.gradle.kts  // <1>
├── sub-project-1
│   └── build.gradle.kts // <2>
├── sub-project-2
│   └── build.gradle.kts // <2>
└── sub-project-3
    └── build.gradle.kts // <2>
----
<1> The `settings.gradle.kts` file should include all subprojects.
<2> Each subproject should have its own `build.gradle.kts` file.

[[sec:project_standard]]
== Multi-Project standards

The Gradle community has two standards for multi-project build structures:

1. **<<sharing_build_logic_between_subprojects.adoc#sec:using_buildsrc,Multi-Project Builds using buildSrc>>** - where `buildSrc` is a subproject-like directory at the Gradle project root containing all the build logic.
2. **<<composite_builds.adoc#composite_builds,Composite Builds>>** - a build that includes other builds where `build-logic` is a build directory at the Gradle project root containing reusable build logic.

image::multi-project-standards.png[]

=== 1. Multi-Project Builds using `buildSrc`

Multi-project builds allow you to organize projects with many modules, wire dependencies between those modules, and easily share common build logic amongst them.

For example, a build that has many modules called `mobile-app`, `web-app`, `api`, `lib`, and `documentation` could be structured as follows:

[source,text]
----
.
├── gradle
├── gradlew
├── settings.gradle.kts
├── buildSrc
│   ├── build.gradle.kts
│   └── src/main/kotlin/shared-build-conventions.gradle.kts
├── mobile-app
│   └── build.gradle.kts
├── web-app
│   └── build.gradle.kts
├── api
│   └── build.gradle.kts
├── lib
│   └── build.gradle.kts
└── documentation
    └── build.gradle.kts
----

The modules will have dependencies between them such as `web-app` and `mobile-app` depending on `lib`.
This means that in order for Gradle to build `web-app` or `mobile-app`, it must build `lib` first.

In this example, the root settings file will look as follows:

.settings.gradle.kts
[source,kotlin]
----
include("mobile-app", "web-app", "api", "lib", "documentation")
----

NOTE: The order in which the subprojects (modules) are included does not matter.

The `buildSrc` directory is automatically recognized by Gradle.
It is a good place to define and maintain shared configuration or imperative build logic, such as custom tasks or plugins.

`buildSrc` is automatically included in your build as a special subproject if a `build.gradle(.kts)` file is found under `buildSrc`.

If the `java` plugin is applied to the `buildSrc` project, the compiled code from `buildSrc/src/main/java` is put in the classpath of the root build script, making it available to any subproject (`web-app`, `mobile-app`, `lib`, etc...) in the build.

Consult how to declare <<sharing_build_logic_between_subprojects.adoc#sec:using_buildsrc, dependencies between subprojects>> to learn more.

=== 2. Composite Builds

Composite Builds, also referred to as _included builds_, are best for sharing logic between builds (_not subprojects_) or isolating access to shared build logic (i.e., convention plugins).

Let's take the previous example.
The logic in `buildSrc` has been turned into a project that contains plugins and can be published and worked on independently of the root project build.

The plugin is moved to its own build called `build-logic` with a build script and settings file:

[source]
----
.
├── gradle
├── gradlew
├── settings.gradle.kts
├── build-logic
│   ├── settings.gradle.kts
│   └── conventions
│       ├── build.gradle.kts
│       └── src/main/kotlin/shared-build-conventions.gradle.kts
├── mobile-app
│   └── build.gradle.kts
├── web-app
│   └── build.gradle.kts
├── api
│   └── build.gradle.kts
├── lib
│   └── build.gradle.kts
└── documentation
    └── build.gradle.kts
----

NOTE: The fact that `build-logic` is located in a subdirectory of the root project is irrelevant. The folder could be located outside the root project if desired.

The root settings file includes the entire `build-logic` *build*:

.settings.gradle.kts
[source]
----
pluginManagement {
    includeBuild("build-logic")
}
include("mobile-app", "web-app", "api", "lib", "documentation")
----

Consult how to <<composite_builds#defining_composite_builds,create composite builds>> with `includeBuild` to learn more.

[[sec:project_path]]
== Multi-Project path

A project path has the following pattern: it starts with an optional colon, which denotes the root project.

The root project, `:`, is the only project in a path not specified by its name.

The rest of a project path is a colon-separated sequence of project names, where the next project is a subproject of the previous project:

[source]
----
:sub-project-1
----

You can see the project paths when running `gradle projects`:

[source]
----
------------------------------------------------------------
Root project 'project'
------------------------------------------------------------

Root project 'project'
+--- Project ':sub-project-1'
\--- Project ':sub-project-2'
----

Project paths usually reflect the filesystem layout, but there are exceptions.
Most notably for <<composite_builds#defining_composite_builds,composite builds>>.

[[sec:identifying_project_structure]]
== Identifying project structure

You can use the `gradle projects` command to identify the project structure.

As an example, let's use a multi-project build with the following structure:
----
> gradle -q projects
----
----
include::{snippetsPath}/java/multiproject/tests/listProjects.out[]
----

Multi-project builds are collections of tasks you can run.
The difference is that you may want to control _which_ project's tasks get executed.

The following sections will cover your two options for executing tasks in a multi-project build.

[[sec:executing_tasks_by_name]]
=== Executing tasks by name

The command `gradle test` will execute the `test` task in any subprojects relative to the current working directory that has that task.

If you run the command from the root project directory, you will run `test` in _api_, _shared_, _services:shared_ and _services:webservice_.

If you run the command from the _services_ project directory, you will only execute the task in _services:shared_ and _services:webservice_.

The basic rule behind Gradle's behavior is to *execute all tasks down the hierarchy with _this_ name*.
And *complain if there is _no_ such task found* in any of the subprojects traversed.

NOTE: Some task selectors, like `help` or `dependencies`, will only run the task on the project they are invoked on and not on all the subprojects to reduce the amount of information printed on the screen.

[[sec:executing_tasks_by_fully_qualified_name]]
=== Executing tasks by fully qualified name

You can use a task's fully qualified name to execute a specific task in a particular subproject.
For example: `gradle :services:webservice:build` will run the `build` task of the _webservice_ subproject.

The fully qualified name of a task is its <<sec:project_path,project path>> plus the task name.

This approach works for any task, so if you want to know what tasks are in a particular subproject, use the `tasks` task, e.g. `gradle :services:webservice:tasks`.

[[sec:multiproject_build_and_test]]
== Multi-Project building and testing

The `build` task is typically used to compile, test, and check a single project.

In multi-project builds, you may often want to do all of these tasks across various projects.
The `buildNeeded` and `buildDependents` tasks can help with this.

In <<declaring_dependencies_between_subprojects#javadependencies_2,this example>>, the `:services:person-service` project depends on both the `:api` and `:shared` projects.
The `:api` project also depends on the `:shared` project.

Assuming you are working on a single project, the `:api` project, you have been making changes but have not built the entire project since performing a `clean`.
You want to build any necessary supporting JARs but only perform code quality and unit tests on the parts of the project you have changed.

The `build` task does this:

====
[.multi-language-sample]
=====
----
$ gradle :api:build

include::{snippetsPath}/multiproject/dependencies-java/tests/multitestingBuild.out[]
----
=====
====

If you have just gotten the latest version of the source from your version control system, which included changes in other projects that `:api` depends on, you might want to build all the projects you depend on AND test them too.

The `buildNeeded` task builds AND tests all the projects from the project dependencies of the `testRuntime` configuration:

====
[.multi-language-sample]
=====
----
$ gradle :api:buildNeeded

include::{snippetsPath}/multiproject/dependencies-java/tests/multitestingBuildNeeded.out[]
----
=====
====

You may want to refactor some part of the `:api` project used in other projects.
If you make these changes, testing only the `:api` project is insufficient.
You must test all projects that depend on the `:api` project.

The `buildDependents` task tests ALL the projects that have a project dependency (in the testRuntime configuration) on the specified project:

====
[.multi-language-sample]
=====
----
$ gradle :api:buildDependents

include::{snippetsPath}/multiproject/dependencies-java/tests/multitestingBuildDependents.out[]
----
=====
====

Finally, you can build and test everything in all projects.
Any task you run in the root project folder will cause that same-named task to be run on all the children.

You can run `gradle build` to build and test ALL projects.

Consult the <<multi_project_builds.adoc#multi_project_builds,Structuring Builds chapter>> to learn more.

[.text-right]
**Next Step:** <<build_lifecycle.adoc#build_lifecycle,Learn about the Gradle Build Lifecycle>> >>
