Gradle 对 Maven POM 配置文件的支持

Maven 配置文件 提供了在特定条件下自定义构建时元数据的能力,例如,如果设置了特定系统属性。一个典型的用例是在不同的运行时环境(例如 Linux 与 Windows)中应用某些配置。例如,正在构建的项目可能需要在这些不同的平台上使用不同的依赖项。

在 Gradle 项目中实现构建时配置文件

如果你仔细想想,Maven 配置文件在逻辑上不过是有限的 if 语句。Gradle 不需要为此专门构造。为什么呢?Gradle 使用编程语言而不是 XML 来定义构建模型。这使你能够使用编程语言中提供的全部表达范围来定义你的配置标准。Gradle 的模型更丰富、更灵活,允许更细粒度地表达 Maven 配置文件通常用于的各种事物。一个非常简单且常用的模式是将条件逻辑拆分为不同的脚本插件,以使条件构建逻辑尽可能模块化和可维护。以下代码片段演示了这种实现

if (project.hasProperty('env') && project.getProperty('env') == 'prod') {
    apply from: 'gradle/production.gradle'
} else {
    apply from: 'gradle/development.gradle'
}

上述方法允许您在任何情况下根据需要随意表达不同的配置。这类似于 Maven 的 profile 方法,但更简洁、更灵活。

表达差异的条件配置的另一种方法是将差异作为一等公民。 AndroidC/C++ Gradle 插件采用了这种方法。这表明 Gradle 团队认为对于大多数场景来说,这是一种更好的方法:将构建定义中的差异作为一等公民,而不是以条件方式表达。这种将差异作为一等公民的方法正在被添加到 基于 JVM 的插件 中,以满足诸如 JDK 兼容性之类的差异,并深度嵌入到 Gradle 的依赖管理引擎中。

使用依赖于 profile 的 Maven 依赖项

我们已经讨论了 Maven profile 在配置构建中的作用以及 Gradle 中的替代方法。由于 Gradle 支持依赖于基于 POM 的工件,我们还必须考虑 Maven profile 如何影响依赖项解析。

一些发布的 Maven 工件,尤其是在公共 Maven Central 存储库中,依赖于其 POM profile 中声明的信息来进行依赖项解析过程。这种做法 被认为是一种应该避免的反模式,因为它会影响构建的可重复性。然而,它在实践中被使用,Gradle 1.12 引入了对影响依赖项解析的某些 profile 使用的支持。

Gradle 中支持的 profile 条件

Gradle 考虑了两个激活条件

  1. 默认情况下处于 活动状态 的 profile(在 Gradle 1.12 及更高版本中可用)
  2. 没有系统属性的情况下处于活动状态 的 profile(在 Gradle 2.0 及更高版本中可用)

让我们看看演示这两个用例的示例。

默认情况下处于活动状态的 profile

profile 可以被认为是默认情况下处于活动状态。此行为由激活元素 activeByDefault 控制。让我们考虑发布的 POM 文件中的以下 profile 部分

<project>
    ...
    <profiles>
        <profile>
            <id>profile-1</id>
            <activation>
                <activeByDefault>true</activeByDefault>
            </activation>
            <dependencies>
                <dependency>
                    <groupId>org.apache.commons</groupId>
                    <artifactId>commons-lang3</artifactId>
                    <version>3.3.2</version>
                </dependency>
            </dependencies>
        </profile>
    </profiles>
</project>

我们可以看到元素 activeByDefault 被设置为 true。从 Gradle 解析相应的工件后,名为 profile-1 的 profile 将变为活动状态。此 profile 将依赖项 org.apache.commons:commons-lang3:3.3.2 声明为传递依赖项。反过来,Gradle 将负责解析此依赖项。

在没有系统属性的情况下处于活动状态的 profile

除了 activeByDefault 之外,还可以通过特定系统属性的缺失来触发配置文件的激活。让我们看看另一个使用这种配置文件激活类型的 POM 文件。

<project>
    ...
    <profiles>
        <profile>
            <id>profile-2</id>
            <property>
                <name>!env.type</name>
            </property>
        </profile>
    </profiles>
</project>

这个 POM 文件将在系统属性 env.type 未定义时激活名为 profile-2 的配置文件。

依赖解析的替代方法

我们已经了解了 Maven 配置文件如何用于表达构建配置中的差异,以及这种差异如何影响在使用配置文件作为其运行时定义的一部分的 Maven 工件时 Gradle 依赖解析。我们还了解了下一代 Gradle 插件(Android、C/C++)如何采用不同的方法来处理差异,使其成为一等公民,并且这种概念也正在应用于 Gradle 对通用 JVM 语言的支持。这也对依赖解析产生了深远的影响,类似于 Maven 配置文件对依赖解析的影响。

将差异作为构建模型中的一等公民的一个重要优势是,可以利用这些信息来提供变体感知的依赖解析。例如,在为 x86 架构构建包含调试符号的二进制文件时,应该使用声明的依赖项的 x86 变体,并且最好使用包含调试符号的变体(如果可用)。这将自动对整个传递依赖关系图强制执行。在软件构建和依赖管理中,有无数的差异情况。

Gradle 的创始人兼 Gradle Inc. 首席执行官 Hans Dockter 最近发布了 2014 年 Gradle 路线图,其中您将看到“变体感知依赖管理”作为当前正在进行的关键项目。预计在未来一年中,将在这一领域推出新的 Gradle 功能。

讨论