构建 Gradle 项目以优化构建性能非常重要。多项目构建是 Gradle 中的标准。

构建构建1

多项目构建由一个根项目和一个或多个子项目组成。 Gradle 可以在一次执行中构建根项目和任意数量的子项目。

项目地点

多项目构建在 Gradle 视为根路径的目录中包含单个根项目:.

子项目物理上位于根路径下:./subproject

子项目有一个 path,它表示该子项目在多项目构建中的位置。大多数情况下,项目路径与其在文件系统中的位置一致。

项目结构在settings.gradle(.kts)文件中创建。设置文件必须存在于根目录中。

简单的多项目构建

让我们看一个基本的多项目构建示例,其中包含一个根项目和一个子项目。

根项目名为basic-multiproject,位于您计算机上的某个位置。从Gradle的角度来看,根目录是顶级目录.

该项目包含一个名为的子项目./app

.
├── app
│   ...
│   └── build.gradle.kts
└── settings.gradle.kts
.
├── app
│   ...
│   └── build.gradle
└── settings.gradle

这是启动任何 Gradle 项目的推荐项目结构。 build init 插件还会生成遵循此结构的骨架项目 - 具有单个子项目的根项目:

settings.gradle(.kts)文件向 Gradle 描述了项目结构:

settings.gradle.kts
rootProject.name = "basic-multiproject"
include("app")
settings.gradle
rootProject.name = 'basic-multiproject'
include 'app'

app在这种情况下,Gradle 将在目录中查找子项目的构建文件./app

您可以通过运行以下命令查看多项目构建的结构projects

$ ./gradlew -q projects

------------------------------------------------------------
Root project 'basic-multiproject'
------------------------------------------------------------

Root project 'basic-multiproject'
\--- Project ':app'

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

在此示例中,app子项目是一个 Java 应用程序,它应用应用程序插件并配置主类。应用程序打印Hello World到控制台:

app/build.gradle.kts
plugins {
    id("application")
}

application {
    mainClass = "com.example.Hello"
}
app/build.gradle
plugins {
    id 'application'
}

application {
    mainClass = 'com.example.Hello'
}
app/src/main/java/com/example/Hello.java
package com.example;

public class Hello {
    public static void main(String[] args) {
        System.out.println("Hello, world!");
    }
}

run您可以通过从项目根目录中的应用程序插件执行任务来运行应用程序:

$ ./gradlew -q run
Hello, world!

添加子项目

在设置文件中,可以使用以下include方法将另一个子项目添加到根项目中:

settings.gradle.kts
include("project1", "project2:child1", "project3:child1")
settings.gradle
include 'project1', 'project2:child1', 'project3:child1'

include方法将项目路径作为参数。假定项目路径等于相对物理文件系统路径。例如,路径services:api默认映射到文件夹./services/api(相对于项目 root .)。

有关如何使用项目路径的更多示例可以在Settings.include(java.lang.String[])的 DSL 文档中找到。

让我们添加另一个子项目来lib调用之前创建的项目。

我们需要做的就是include在根设置文件中添加另一条语句:

settings.gradle.kts
rootProject.name = "basic-multiproject"
include("app")
include("lib")
settings.gradle
rootProject.name = 'basic-multiproject'
include 'app'
include 'lib'

lib然后 Gradle 将在目录中查找新子项目的构建文件./lib/

.
├── app
│   ...
│   └── build.gradle.kts
├── lib
│   ...
│   └── build.gradle.kts
└── settings.gradle.kts
.
├── app
│   ...
│   └── build.gradle
├── lib
│   ...
│   └── build.gradle
└── settings.gradle

项目描述

为了进一步向 Gradle 描述项目架构,设置文件提供了项目描述符

您可以随时在设置文件中修改这些描述符。

要访问描述符,您可以:

settings.gradle.kts
include("project-a")
println(rootProject.name)
println(project(":project-a").name)
settings.gradle
include('project-a')
println rootProject.name
println project(':project-a').name

使用此描述符,您可以更改项目的名称、项目目录和构建文件:

settings.gradle.kts
rootProject.name = "main"
include("project-a")
project(":project-a").projectDir = file("custom/my-project-a")
project(":project-a").buildFileName = "project-a.gradle.kts"
settings.gradle
rootProject.name = 'main'
include('project-a')
project(':project-a').projectDir = file('custom/my-project-a')
project(':project-a').buildFileName = 'project-a.gradle'

有关详细信息,请参阅API 文档中的ProjectDescriptor类。

修改子项目路径

让我们假设一个具有以下结构的项目:

.
├── app
│   ...
│   └── build.gradle.kts
├── subs // Gradle may see this as a subproject
│   └── web // Gradle may see this as a subproject
│       └── my-web-module // Intended subproject
│           ...
│           └── build.gradle.kts
└── settings.gradle.kts
.
├── app
│   ...
│   └── build.gradle
├── subs // Gradle may see this as a subproject
│   └── web // Gradle may see this as a subproject
│       └── my-web-module // Intended subproject
│           ...
│           └── build.gradle
└── settings.gradle

如果你settings.gradle(.kts)看起来像这样:

include(':subs:web:my-web-module')

Gradle 看到一个子项目的逻辑项目名称为 ,:subs:web:my-web-module并且两个(可能是无意的)其他子项目的逻辑名称为:subs:subs:web。这可能会导致幻像构建目录,特别是在使用allprojects{}或时subproject{}

为了避免这种情况,您可以使用:

include(':subs:web:my-web-module')
project(':subs:web:my-web-module').projectDir = "subs/web/my-web-module"

这样您最终只会得到一个名为 的子项目:subs:web:my-web-module

或者您可以使用:

include(':my-web-module')
project(':my-web-module').projectDir = "subs/web/my-web-module"

这样您最终只会得到一个名为 的子项目:my-web-module

因此,虽然物理项目布局相同,但逻辑结果却不同。

命名建议

随着项目的发展,命名和一致性变得越来越重要。为了保持您的构建可维护,我们建议如下:

  1. 保留子项目的默认项目名称:可以在设置文件中配置自定义项目名称。然而,对于开发人员来说,跟踪哪些项目属于哪些文件夹是不必要的额外工作。

  2. 对所有项目名称使用小写连字符-:所有字母均为小写,单词之间用破折号 ( ) 字符分隔。

  3. 在设置文件中定义根项目名称rootProject.name有效地为构建分配一个名称,用于构建扫描等报告中。如果未设置根项目名称,则该名称将是容器目录名称,这可能不稳定(即,您可以在任何目录中查看您的项目)。如果未设置根项目名称并检出到文件系统的根(例如,/C:\),则该名称将随机生成。