Gradle 支持多项目构建。

gradle basic 9

虽然一些小型项目和单体应用程序可能包含一个构建文件和源代码树,但通常更常见的情况是将项目拆分为更小的相互依赖的模块。“相互依赖”一词至关重要,因为您通常希望通过单个构建将许多模块链接在一起。

Gradle 通过多项目构建支持此场景。这有时称为多模块项目。Gradle 将模块称为子项目。

多项目构建由一个根项目和一个或多个子项目组成。

多项目结构

以下是包含两个子项目的的多项目构建结构

multi project structure

目录结构应如下所示

├── .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 settings.gradle.kts 文件应包含所有子项目。
2 每个子项目都应有自己的 build.gradle.kts 文件。

多项目标准

Gradle 社区对多项目构建结构有两个标准

  1. 使用 buildSrc 的多项目构建 - 其中 buildSrc 是 Gradle 项目根目录中的类似子项目的目录,包含所有构建逻辑。

  2. 复合构建 - 包含其他构建的构建,其中 build-logic 是 Gradle 项目根目录中的构建目录,包含可重用的构建逻辑。

multi project standards

1. 使用 buildSrc 的多项目构建

多项目构建允许你组织具有多个模块的项目,连接这些模块之间的依赖关系,并在它们之间轻松共享常见的构建逻辑。

例如,一个具有许多模块的构建,称为 mobile-appweb-appapilibdocumentation,可以按如下方式构建

.
├── 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

模块之间将有依赖关系,例如 web-appmobile-app 取决于 lib。这意味着为了让 Gradle 构建 web-appmobile-app,它必须首先构建 lib

在此示例中,根设置文件将如下所示

settings.gradle.kts
include("mobile-app", "web-app", "api", "lib", "documentation")
包含子项目(模块)的顺序无关紧要。

buildSrc 目录由 Gradle 自动识别。这是一个定义和维护共享配置或命令式构建逻辑(例如自定义任务或插件)的好地方。

如果在 buildSrc 下找到 build.gradle(.kts) 文件,则 buildSrc 会作为特殊子项目自动包含在你的构建中。

如果 java 插件应用于 buildSrc 项目,则来自 buildSrc/src/main/java 的编译代码将被放入根构建脚本的类路径中,使其可用于构建中的任何子项目(web-appmobile-applib 等)。

查阅如何声明 子项目之间的依赖关系 以了解更多信息。

2. 复合构建

复合构建,也称为包含构建,最适合在构建(不是子项目)之间共享逻辑或隔离对共享构建逻辑(即约定插件)的访问。

我们来看之前的示例。buildSrc 中的逻辑已变成一个包含插件的项目,并且可以独立于根项目构建发布和处理。

该插件已移至其自己的构建,称为 build-logic,其中包含构建脚本和设置文件

.
├── 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
build-logic 位于根项目的子目录中的事实无关紧要。如果需要,该文件夹可以位于根项目之外。

根设置文件包括整个 build-logic 构建

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

查阅如何使用 includeBuild 创建复合构建 以了解更多信息。

多项目路径

项目路径具有以下模式:它以一个可选的冒号开头,表示根项目。

根项目 : 是路径中唯一一个未按其名称指定的项目。

项目路径的其余部分是项目名称的冒号分隔序列,其中下一个项目是前一个项目的子项目

:sub-project-1

运行 gradle projects 时可以看到项目路径

------------------------------------------------------------
Root project 'project'
------------------------------------------------------------

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

项目路径通常反映文件系统布局,但也有例外。最值得注意的是 复合构建

识别项目结构

可以使用 gradle projects 命令来识别项目结构。

例如,让我们使用具有以下结构的多项目构建

> gradle -q projects
------------------------------------------------------------
Root project 'multiproject'
------------------------------------------------------------

Root project 'multiproject'
+--- Project ':api'
+--- Project ':services'
|    +--- Project ':services:shared'
|    \--- Project ':services:webservice'
\--- Project ':shared'

To see a list of the tasks of a project, run gradle <project-path>:tasks
For example, try running gradle :api:tasks

多项目构建是可以运行的任务集合。不同之处在于你可能希望控制哪些项目的任务得到执行。

以下部分将介绍在多项目构建中执行任务的两种选择。

按名称执行任务

命令 gradle test 将执行相对于具有该任务的当前工作目录的任何子项目中的 test 任务。

如果你从根项目目录运行该命令,则将在 apisharedservices:sharedservices:webservice 中运行 test

如果你从 services 项目目录运行该命令,则只会在 services:sharedservices:webservice 中执行该任务。

Gradle 行为背后的基本规则是执行层次结构中所有具有名称的任务。并且如果在遍历的任何子项目中没有找到此类任务,则会发出抱怨

一些任务选择器(如 helpdependencies)只会对调用它们的项目运行任务,而不会对所有子项目运行任务,以减少屏幕上打印的信息量。

按完全限定名称执行任务

可以使用任务的完全限定名称在特定子项目中执行特定任务。例如:gradle :services:webservice:build 将运行 webservice 子项目的 build 任务。

任务的完全限定名称是其 项目路径 加上任务名称。

此方法适用于任何任务,因此如果你想知道特定子项目中有哪些任务,请使用 tasks 任务,例如 gradle :services:webservice:tasks

多项目构建和测试

build 任务通常用于编译、测试和检查单个项目。

在多项目构建中,你可能经常希望在各个项目中执行所有这些任务。buildNeededbuildDependents 任务可以帮助实现这一点。

此示例中,:services:person-service 项目依赖于 :api:shared 项目。:api 项目也依赖于 :shared 项目。

假设您正在处理单个项目 :api 项目,您一直在进行更改,但自执行 clean 以来尚未构建整个项目。您希望构建任何必要的支持 JAR,但仅对您已更改的项目部分执行代码质量和单元测试。

build 任务执行此操作

$ gradle :api:build

> Task :shared:compileJava
> Task :shared:processResources
> Task :shared:classes
> Task :shared:jar
> Task :api:compileJava
> Task :api:processResources
> Task :api:classes
> Task :api:jar
> Task :api:assemble
> Task :api:compileTestJava
> Task :api:processTestResources
> Task :api:testClasses
> Task :api:test
> Task :api:check
> Task :api:build

BUILD SUCCESSFUL in 0s

如果您刚刚从版本控制系统获取了最新版本的源代码,其中包括 :api 所依赖的其他项目中的更改,您可能希望构建您所依赖的所有项目并对其进行测试。

buildNeeded 任务从 testRuntime 配置的项目依赖项构建并测试所有项目

$ gradle :api:buildNeeded

> Task :shared:compileJava
> Task :shared:processResources
> Task :shared:classes
> Task :shared:jar
> Task :api:compileJava
> Task :api:processResources
> Task :api:classes
> Task :api:jar
> Task :api:assemble
> Task :api:compileTestJava
> Task :api:processTestResources
> Task :api:testClasses
> Task :api:test
> Task :api:check
> Task :api:build
> Task :shared:assemble
> Task :shared:compileTestJava
> Task :shared:processTestResources
> Task :shared:testClasses
> Task :shared:test
> Task :shared:check
> Task :shared:build
> Task :shared:buildNeeded
> Task :api:buildNeeded

BUILD SUCCESSFUL in 0s

您可能希望重构 :api 项目中用于其他项目的部分。如果您进行这些更改,仅测试 :api 项目是不够的。您必须测试所有依赖于 :api 项目的项目。

buildDependents 任务测试所有对指定项目(在 testRuntime 配置中)具有项目依赖项的项目

$ gradle :api:buildDependents

> Task :shared:compileJava
> Task :shared:processResources
> Task :shared:classes
> Task :shared:jar
> Task :api:compileJava
> Task :api:processResources
> Task :api:classes
> Task :api:jar
> Task :api:assemble
> Task :api:compileTestJava
> Task :api:processTestResources
> Task :api:testClasses
> Task :api:test
> Task :api:check
> Task :api:build
> Task :services:person-service:compileJava
> Task :services:person-service:processResources
> Task :services:person-service:classes
> Task :services:person-service:jar
> Task :services:person-service:assemble
> Task :services:person-service:compileTestJava
> Task :services:person-service:processTestResources
> Task :services:person-service:testClasses
> Task :services:person-service:test
> Task :services:person-service:check
> Task :services:person-service:build
> Task :services:person-service:buildDependents
> Task :api:buildDependents

BUILD SUCCESSFUL in 0s

最后,您可以在所有项目中构建和测试所有内容。您在根项目文件夹中运行的任何任务都将导致在所有子项目上运行同名任务。

您可以运行 gradle build 来构建和测试所有项目。

请参阅构建结构章节以了解更多信息。