多项目打包

在上一节中,您为项目定义了分层目录结构。 完整的项目由一个根目录和每个模块一个子目录组成。 在本节中,您将学习如何使用 Gradle 构建这样的项目结构。

您的起点将是目录树根级别上必需的 build.gradle 文件。 创建一个空的构建脚本并通过运行 gradle 项目来检查参与构建的项目:

$ gradle projects
:projects
------------------------------------------------------------
Root project
------------------------------------------------------------
Root project 'todo'
No sub-projects

Gradle 报告说您只处理一个项目。 当建立一个包含多个项目的构建时,Gradle 的词汇涉及多项目构建。 原因是您将每个模块表示为一个不同的 Gradle 项目。 从现在开始,为了与 Gradle 的语法保持一致,我们将不再使用术语 “模块”; 我们只讨论项目。

位于顶级目录中的总体项目称为根项目,它有自己的权利存在于多项目构建中。 它协调子项目的构建,并可以为它们定义常见或特定的行为。 图 6.3 以图形方式概述了您将要实现的分层项目结构。

image 2024 04 03 17 27 45 500
Figure 1. 图 6.3 To Do 应用程序的分层多项目结构,它定义了三个子项目

到目前为止,我们只处理了单项目构建的 Gradle 配置。 您发现将代码分成多个项目并不那么困难。 缺少的是代表根项目及其子项目的构建支持。 多项目构建中子项目的声明是通过设置(settings)文件完成的。

引入设置文件

设置文件声明实例化项目层次结构所需的配置。 默认情况下,此文件名为 settings.gradle,与根项目的 build.gradle 文件一起创建。 以下列表显示了设置文件的内容。 对于您想要成为构建一部分的每个子项目,您可以使用项目路径的参数调用 include 方法。

清单 6.1 按路径添加子项目的设置文件
// 添加给定的子项目来构建; 传递给 include 方法的参数是项目路径,而不是文件路径
include 'model'
// 不要单独为每个项目调用方法 include,而是将项目的 String[] 传递给单个调用
include 'repository', 'web'

此代码片段中提供的项目路径是相对于根目录的项目目录。 请记住,您还可以对更深层次的项目层次结构进行建模。 冒号字符 (:) 分隔子项目层次结构的每个级别。 例如,如果您想映射目录结构 model/todo/items,则可以通过路径 model:todo:items 添加子项目。

添加设置文件后执行帮助任务 projects 将产生不同的结果:

$ gradle projects
:projects
------------------------------------------------------------
Root project
------------------------------------------------------------
Root project 'todo'
+--- Project ':model'
+--- Project ':repository'
\--- Project ':web'

通过添加单个设置文件,您创建了一个包含一个根项目和三个子项目的多模块构建。 不需要额外的配置。 让我们更深入地了解设置文件的详细信息。 您可能已经猜到它有一个 API 表示形式,您可以使用它来查询和修改构建的配置。

了解设置 API 表示

在 Gradle 组装构建之前,它会创建一个 Settings 类型的实例。 设置接口是设置文件的直接表示。 其主要目的是添加应该参与多项目构建的项目实例。 除了组装多项目构建之外,您还可以在 build.gradle 脚本中执行您习惯的所有操作,因为您可以直接访问 Gradle 和 Project 接口。 图6.4展示了Settings 接口的相关方法及其关联。

这里重要的一点是,您正在针对 settings.gradle 文件中的接口设置实例进行编码。 Settings 接口的任何方法都可以像调用 include 一样直接调用。

接下来,我们将讨论在构建生命周期中何时执行设置文件以及应用哪些规则来解析该文件。

image 2024 04 03 17 37 26 686
Figure 2. 图 6.4 设置 API 表示。 您可以使用Settings实例通过Gradle接口检索项目描述符或项目实例。

从构建文件访问设置

如果在加载和计算设置后需要从 build.gradle 文件访问 Settings 实例,则可以注册生命周期闭包或侦听器。 一个很好的起点是 Gradle#settingsEvaluated(Closure) 方法,它提供 Settings 对象作为闭包参数。

设置执行

回想一下第 4 章,我们讨论了构建的三个不同的生命周期阶段。 您可能已经知道设置文件的代码在哪个阶段被评估和执行。 它需要在初始化阶段发生,然后才能配置任何项目实例,如图 6.5 所示。

image 2024 04 03 17 46 51 293
Figure 3. 图 6.5 设置文件在初始化阶段被评估和执行

执行构建时,Gradle 会自动确定子项目是单项目构建还是多项目构建的一部分。 让我们检查 Gradle 用于确定设置文件是否存在的规则集。

设置文件解析

Gradle 允许您从根项目目录或任何包含构建文件的子项目目录运行构建。 Gradle 如何知道子项目是多项目构建的一部分? 它需要找到设置文件,该文件指示子项目是否包含在多项目构建中。 图 6.6 显示了 Gradle 用于查找设置文件的两步过程。

在步骤 1 中,Gradle 在名为 master 的目录中搜索与当前目录具有相同嵌套级别的设置文件。 如果在步骤 1 中未找到设置文件,Gradle 会从当前目录开始在父目录中搜索设置文件。 对于 subproject2,搜索将为 suproject1 > root。

如果其中一个步骤找到设置文件并且该项目包含在其定义中,则该项目将被视为多项目构建的一部分。 否则,项目将作为单个项目构建执行。

设置文件解析过程中的步骤 2 适用于您之前设置的分层项目布局。 让我们退后一步,检查一下步骤 1 中显示的项目布局。

image 2024 04 03 17 50 10 471
Figure 4. 图 6.6 设置文件解析过程分为两步。

控制设置文件搜索行为

有两个命令行参数有助于确定设置文件的搜索行为:

  • -u, --no-search-upward:告诉 Gradle 不要在父目录中搜索设置文件。 如果您想避免在深度嵌套的项目结构中搜索所有父目录对性能造成影响,则此选项非常有用。

  • -c, --settings-file:指定设置文件的位置。 如果您的设置文件名偏离标准命名约定,您可能需要使用此选项。

分层布局与平面布局

Gradle 项目可以分层结构或平面布局,如图 6.7 所示。 如果参与的项目与根项目位于同一目录级别,则我们称之为平面多项目布局。 因此,这意味着子项目的嵌套级别只能为一层深。 您为项目选择的布局取决于您。 就我个人而言,我更喜欢分层项目布局,因为它为您提供了更细粒度的控制来建模组件。

image 2024 04 03 17 54 32 699
Figure 5. 图 6.7 分层和平面项目布局及其设置文件配置的比较

图 6.7 比较了使用分层布局和平面布局设置待办事项应用程序项目之间的差异。 您必须在其他子项目旁边创建一个专用目录,而不是将构建和设置文件放在项目的根级别。 选择目录名称 master ,以便您可以从子项目执行构建,如上一节所述。 要指示您想要将项目包含在与根项目相同的项目嵌套级别上,请在设置文件中使用方法 includeFlat。

在下一部分中,您将为构建中的每个项目配置构建逻辑。