第八章. 多项目构建简介

Chapter 8. Introduction to multi-project builds

目录
Table of Contents

8.1. 多项目构建的结构 - Structure of a multi-project build
8.2. 执行多项目构建 - Executing a multi-project build

只有最小的项目才会有一个构建文件和源码树,除非它碰巧是一个大规模的整体应用。把一个项目拆分成更小,相互依赖的模块通常更容易理解。然而,“相互依赖”一词很重要,这也是为什么通常希望通过单一的构建将这些模块链接在一起的原因。
Only the smallest of projects has a single build file and source tree, unless it happens to be a massive, monolithic application. It’s often much easier to digest and understand a project that has been split into smaller, inter-dependent modules. The word “inter-dependent” is important, though, and is why you typically want to link the modules together through a single build.

Gradle 通过 多项目 构建支持这种场景。
Gradle supports this scenario through multi-project builds.

8.1. 多项目构建的结构

8.1. Structure of a multi-project build

这类构建有各种各样的形式和规模,但它们确实具有一些共同的特点:
Such builds come in all shapes and sizes, but they do have some common characteristics:

  • 项目的根目录或 master 目录中 一个 settings.gradle 文件

    A settings.gradle file in the root or master directory of the project

  • 根目录或 master 目录中有一个 build.gradle 文件

    A build.gradle file in the root or master directory

  • 子目录有它们自己的 *.gradle 构建文件(某些多项目构建可能会省略子项目构建脚本)

    Child directories that have their own *.gradle build files (some multi-project builds may omit child project build scripts)

settings.gradle 文件告诉 Gradle 项目和子项目的结构。幸运的是,您不必阅读此文件,只需要运行命令 gradle projects即可了解项目结构。以下是在 Gradle 范例中的 Java 多项目 构建上使用该命令的输出结果:
The settings.gradle file tells Gradle how the project and subprojects are structured. Fortunately, you don’t have to read this file simply to learn what the project structure is as you can run the command gradle projects. Here's the output from using that command on the Java multiproject build in the Gradle samples:

示例 8.1. 在构建中列出项目 - Example 8.1. Listing the projects in a build

gradle -q projects的输出结果
Output of gradle -q projects

> gradle -q projects

------------------------------------------------------------
Root project
------------------------------------------------------------

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


这告诉了您multiproject 有三个直接的子项目:apiservicessharedservices 项目有自己的子项目:sharedwebservice。这些映射到目录结构,因此很容易找到它们。例如,您可以在 <root>/services/webservice中找到 webservice
This tells you that multiproject has three immediate child projects: api, services and shared. The services project then has its own children, shared and webservice. These map to the directory structure, so it’s easy to find them. For example, you can find webservice in <root>/services/webservice.

默认情况下,Gradle 使用它找到的 settings.gradle 的目录名称作为根项目的名称。这通常不会导致问题,因为一个项目上的所有开发者都检出相同的目录名。在连续集成服务器上,如 Jenkins ,目录名称可以自动生成,但与 VCS中的名称不匹配。 因此,建议您始终将根项目名称设置为可预测的内容,即使在单个项目构建中也是如此。可以通过设置 rootProject.name来配置根项目名称。
By default, Gradle uses the name of the directory it finds the settings.gradle as the name of the root project. This usually doesn't cause problems since all developers check out the same directory name when working on a project. On Continuous Integration servers, like Jenkins, the directory name may be auto-generated and not match the name in your VCS. For that reason, it's recommended that you always set the root project name to something predictable, even in single project builds. You can configure the root project name by setting rootProject.name.

通常每个项目都有自己的构建文件,但不一定都是。在上面的例子中,services 项目只是一个容器,或者说是其他子项目的分组,对应目录中没有构建文件。但是,multiproject 就有一个用于根项目的构建文件。
Each project will usually have its own build file, but that's not necessarily the case. In the above example, the services project is just a container or grouping of other subprojects. There is no build file in the corresponding directory. However, multiproject does have one for the root project.

build.gradle 通常用于在子项目之间共享通用配置,例如,将相同的插件和依赖应用于所有子项目。它还可用于配置各个子项目,当更喜欢将所有配置都放在一个位置时。 这意味着在了解特定子项目的配置时,你应该始终查看根构建文件。
The root build.gradle is often used to share common configuration between the child projects, for example by applying the same sets of plugins and dependencies to all the child projects. It can also be used to configure individual subprojects when it is preferable to have all the configuration in one place. This means you should always check the root build file when discovering how a particular subproject is being configured.

另外要记住的是,构建文件不一定叫 build.gradle。许多项目将在子项目名称之后命名构建文件,如先前示例中的 api.gradleservices.gradle。这种做法在 IDE 中很方便,因为很难确定在 20 个可能的 build.gradle 文件中,到底哪一个才是您想打开的。 这个小技巧是由 settings.gradle 文件处理的,但作为构建用户,您不需要知道它是如何实现的。只需要查看子项目目录,找到带有 .gradle 后缀的文件。
Another thing to bear in mind is that the build files might not be called build.gradle. Many projects will name the build files after the subproject names, such as api.gradle and services.gradle from the previous example. Such an approach helps a lot in IDEs because it’s tough to work out which build.gradle file out of twenty possibilities is the one you want to open. This little piece of magic is handled by the settings.gradle file, but as a build user you don’t need to know the details of how it’s done. Just have a look through the child project directories to find the files with the .gradle suffix.

一旦您知道哪些子项目可用,对于构建用户,那么关键问题就是如何执行项目中的任务。
Once you know what subprojects are available, the key question for a build user is how to execute the tasks within the project.

8.2. 执行多项目构建

8.2. Executing a multi-project build

从用户的角度看,多项目构建仍然是您可以运行的任务集。差别在于您可能想要控制 哪个 项目的任务执行。这里有两个选项:
From a user's perspective, multi-project builds are still collections of tasks you can run. The difference is that you may want to control which project's tasks get executed. You have two options here:

  • 切换到您感兴趣的子项目所对应的目录,并像正常一样只执行 gradle <task>

    Change to the directory corresponding to the subproject you’re interested in and just execute gradle <task> as normal.

  • 使用任何目录中的限定任务名,尽管这通常是从根目录进行的。例如:gradle :services:webservice:build 将构建 webservice 子项目及其依赖的任何子项目。

    Use a qualified task name from any directory, although this is usually done from the root. For example: gradle :services:webservice:build will build the webservice subproject and any subprojects it depends on.

第一种方法与单项目用法相似,但在多项目构建的情况下, Gradle 的工作方式略有不同。命令 gradle test 将执行当前工作目录下,所有子项目的 test 任务,如果该子项目有的话。因此,如果从根项目目录运行命令,那么就会运行 apisharedservices:sharedservices:webservice中的 test 任务。如果从 services 项目目录运行该命令,那么将只执行 services:sharedservices:webservice中的该任务。
The first approach is similar to the single-project use case, but Gradle works slightly differently in the case of a multi-project build. The command gradle test will execute the test task in any subprojects, relative to the current working directory, that have that task. So if you run the command from the root project directory, you’ll run test in api, shared, services:shared and services:webservice. If you run the command from the services project directory, you’ll only execute the task in services:shared and services:webservice.

为了对所执行的内容进行更多控制,请使用限定名(即上述第二种方法)。这些路径与目录路径一样,但使用“:”而不是“/”或“\”。如果路径以 ":" 开头,那么将相对于根项目解析路径。换句话说,前导“:”表示根项目本身,所有其他冒号都是路径分隔符。
For more control over what gets executed, use qualified names (the second approach mentioned). These are paths just like directory paths, but use ‘:’ instead of ‘/’ or ‘\’. If the path begins with a ‘:’, then the path is resolved relative to the root project. In other words, the leading ‘:’ represents the root project itself. All other colons are path separators.

此方法适用于任何任务,因此,如果要了解特定子项目中的任务,只需使用 takss 任务,例如 gradle :services:webservice:task
This approach works for any task, so if you want to know what tasks are in a particular subproject, just use the tasks task, e.g. gradle :services:webservice:tasks .

无论您使用哪种技术来执行任务,Gradle 都将负责构建目标项目所依赖的任何子项目。您不必担心项目间的依赖关系。如果您对如何配置此项感兴趣,那么可以 在用户指南的后面部分阅读有关编写多项目构建的内容。
Regardless of which technique you use to execute tasks, Gradle will take care of building any subprojects that the target depends on. You don’t have to worry about the inter-project dependencies yourself. If you’re interested in how this is configured, you can read about writing multi-project builds later in the user guide.

最后要注意的是,当您使用 Gradle 包装器时,第一种方法无法使用,因为如果您不在项目根目录中,那么必须指定包装器脚本的路径。例如,如果您在 webservice 子项目目录中,那么必须运行 ../../gradlew build
There’s one last thing to note. When you’re using the Gradle wrapper, the first approach doesn’t work well because you have to specify the path to the wrapper script if you’re not in the project root. For example, if you’re in the webservice subproject directory, you would have to run ../../gradlew build.

以上就是你作为一个构建用户,关于多项目构建所需要了解的所有内容了。现在,您能够确定构建是否为多项目,您还可以理解该构建的结构。最后,您可以执行特定子项目中的任务。
That’s all you really need to know about multi-project builds as a build user. You can now identify whether a build is a multi-project one and you can discover its structure. And finally, you can execute tasks within specific subprojects.