变体感知匹配 部分所述,属性为变体赋予语义,并由 Gradle 的依赖管理引擎用于选择最佳匹配的变体。

作为 Gradle 的用户,属性通常被隐藏为实现细节。但了解 Gradle 及其核心插件定义的 *标准属性* 可能很有用。

作为插件作者,这些属性及其定义方式可以作为您在生态系统插件中 构建自己的属性集 的基础。

Gradle 定义的标准属性

Gradle 定义了一系列由 Gradle 的核心插件使用的标准属性。

与生态系统无关的标准属性

表 1. 生态系统无关的标准变体属性
属性名称 描述 兼容性和消除歧义规则

org.gradle.usage

指示变体的主要用途

Usage 值由 Usage 中定义的常量构建

遵循生态系统语义(例如,java-runtime 可以代替 java-api 使用,但反之则不行)

org.gradle.category

指示此软件组件的类别

Category 值由 Category 中定义的常量构建

遵循生态系统语义(例如,library 是 JVM 上的默认值,其他情况下没有兼容性)

org.gradle.libraryelements

指示 org.gradle.category=library 变体的内容

LibraryElements 值由 LibraryElements 中定义的常量构建

遵循生态系统语义(例如,在 JVM 世界中,jar 是默认值,并且与 classes 兼容)

org.gradle.docstype

指示 org.gradle.category=documentation 变体的内容

DocsType 值由 DocsType 中定义的常量构建

没有默认值,没有兼容性

org.gradle.dependency.bundling

指示如何访问变体的依赖项。

Bundling 值由 Bundling 中定义的常量构建

遵循生态系统语义(例如,在 JVM 世界中,embeddedexternal 兼容)

org.gradle.verificationtype

指示哪种验证任务生成了此输出。

VerificationType 值由 VerificationType 中定义的常量构建

没有默认值,没有兼容性

Category 属性与孵化值 org.gradle.category=verification 一起出现在变体上时,该变体被认为是仅在验证时使用的变体。

这些变体旨在仅包含运行验证任务的结果,例如测试结果或代码覆盖率报告。它们**不可发布**,如果添加到已发布的组件中,将产生错误。

表 2. 生态系统无关的标准组件属性
属性名称 描述 兼容性和消除歧义规则

org.gradle.status

组件级别属性,派生

基于 状态方案,默认方案基于源代码库。

基于正在使用的方案

JVM 生态系统特定属性

除了上面定义的生态系统独立属性之外,JVM 生态系统还添加了以下属性

表 3. JVM 生态系统标准组件属性
属性名称 描述 兼容性和消除歧义规则

org.gradle.jvm.version

指示 JVM 版本兼容性。

对于 Java 1.4 及之前版本,使用 1. 之后的版本作为整数,对于 Java 5 及之后版本,使用主版本。

默认为 Gradle 使用的 JVM 版本,较低版本与较高版本兼容,优先选择最高兼容版本。

org.gradle.jvm.environment

指示变体是否针对特定 JVM 环境进行了优化。

常见值包括 standard-jvmandroid。允许使用其他值。

如果有多个变体可用,则使用此属性来优先选择一个变体,但通常所有值都是兼容的。默认值为 standard-jvm

org.gradle.testsuite.name

指示生成此输出的 TestSuite 的名称。

值为 Suite 的名称。

没有默认值,没有兼容性

org.gradle.testsuite.target.name

指示生成此输出的 TestSuiteTarget 的名称。

值为 Target 的名称。

没有默认值,没有兼容性

org.gradle.testsuite.type

指示测试套件的类型(单元测试、集成测试、性能测试等)。

TestSuiteType 值构建自 TestSuiteType 中定义的常量或用户定义的测试套件类型的其他自定义值。

没有默认值,没有兼容性

JVM 生态系统还包含一些针对不同属性的兼容性和消除歧义规则。想要了解更多信息的读者可以查看 org.gradle.api.internal.artifacts.JavaEcosystemSupport 的代码。

原生生态系统特定属性

除了上面定义的生态系统独立属性之外,原生生态系统还添加了以下属性

表 4. 原生生态系统标准组件属性
属性名称 描述 兼容性和消除歧义规则

org.gradle.native.debuggable

指示二进制文件是否使用调试符号构建

布尔值

N/A

org.gradle.native.optimized

指示二进制文件是否使用优化标志构建

布尔值

N/A

org.gradle.native.architecture

指示二进制文件的目标架构

MachineArchitecture 值由 MachineArchitecture 中定义的常量构建。

org.gradle.native.operatingSystem

指示二进制文件的目标操作系统。

OperatingSystemFamily 值由 OperatingSystemFamily 中定义的常量构建。

Gradle 插件生态系统特定属性

对于 Gradle 插件开发,从 Gradle 7.0 开始支持以下属性。Gradle 插件变体可以通过此属性指定与 Gradle API 版本的兼容性。

表 5. Gradle 插件生态系统标准组件属性
属性名称 描述 兼容性和消除歧义规则

org.gradle.plugin.api‑version

指示 Gradle API 版本兼容性。

有效的 Gradle 版本字符串。

默认为当前运行的 Gradle,较低的版本与较高的版本兼容,优先选择最高兼容版本。

声明自定义属性

如果您正在扩展 Gradle,例如通过为另一个生态系统编写插件,如果您希望在插件中支持变体感知的依赖管理功能,则声明自定义属性可能是一个选择。但是,如果您也尝试发布库,则应谨慎。新属性的语义通常通过插件定义,插件可以携带 兼容性消歧 规则。因此,使用为特定生态系统发布的库的构建也需要应用相应的插件才能正确解释属性。如果您的插件面向更广泛的受众,即如果它是公开可用的并且库发布到公共存储库,则定义新属性实际上扩展了 Gradle 模块元数据的语义,并带来了责任。例如,对已发布属性的支持不应再次删除,或者应在插件的未来版本中通过某种兼容性层进行处理。

在构建脚本或插件中创建属性

属性是类型化的。可以通过 Attribute<T>.of 方法创建属性。

示例 1. 定义属性
build.gradle.kts
// An attribute of type `String`
val myAttribute = Attribute.of("my.attribute.name", String::class.java)
// An attribute of type `Usage`
val myUsage = Attribute.of("my.usage.attribute", Usage::class.java)
build.gradle
// An attribute of type `String`
def myAttribute = Attribute.of("my.attribute.name", String)
// An attribute of type `Usage`
def myUsage = Attribute.of("my.usage.attribute", Usage)

属性类型支持大多数 Java 基本类;例如 StringInteger;或任何扩展 org.gradle.api.Named 的类。属性必须在 dependencies 处理程序上的属性模式中声明。

build.gradle.kts
dependencies.attributesSchema {
    // registers this attribute to the attributes schema
    attribute(myAttribute)
    attribute(myUsage)
}
build.gradle
dependencies.attributesSchema {
    // registers this attribute to the attributes schema
    attribute(myAttribute)
    attribute(myUsage)
}

然后可以配置配置以设置属性的值。

build.gradle.kts
configurations {
    create("myConfiguration") {
        attributes {
            attribute(myAttribute, "my-value")
        }
    }
}
build.gradle
configurations {
    myConfiguration {
        attributes {
            attribute(myAttribute, 'my-value')
        }
    }
}

对于类型扩展 Named 的属性,属性的值**必须**通过对象工厂创建。

示例 4. 命名属性
build.gradle.kts
configurations {
    "myConfiguration" {
        attributes {
            attribute(myUsage, project.objects.named(Usage::class.java, "my-value"))
        }
    }
}
build.gradle
configurations {
    myConfiguration {
        attributes {
            attribute(myUsage, project.objects.named(Usage, 'my-value'))
        }
    }
}

属性匹配

属性兼容性规则

属性允许引擎选择兼容的变体。在某些情况下,生产者可能没有完全满足消费者要求的内容,但可能有一个可以使用的变体。

例如,如果消费者要求库的 API,而生产者没有完全匹配的变体,则可以考虑运行时变体兼容。这在发布到外部存储库的库中很常见。在这种情况下,我们知道即使没有完全匹配(API),我们仍然可以针对运行时变体进行编译(它包含更多我们编译所需的内容,但仍然可以使用)。

Gradle 提供了 属性兼容性规则,可以为每个属性定义这些规则。兼容性规则的作用是解释哪些属性值根据消费者的要求是兼容的。

属性兼容性规则必须通过 属性匹配策略 注册,您可以从 属性模式 中获取该策略。

属性消歧规则

由于一个属性可以有多个值是兼容的,因此 Gradle 需要在所有兼容的候选者中选择“最佳”候选者。这称为“消歧”。

这是通过实现 属性消歧规则 来完成的。

属性消歧规则必须通过 属性匹配策略 注册,您可以从 属性模式 中获取该策略,它是 DependencyHandler 的成员。

变体属性匹配算法

当一个组件有多个不同的变体,并且每个变体有多个不同的属性时,找到最佳变体可能会变得很复杂。Gradle 的依赖解析引擎在寻找最佳结果(或失败)时执行以下算法。

  1. 每个候选者的属性值都会与消费者的请求属性值进行比较。如果候选者的值与消费者的值完全匹配,通过了属性的兼容性规则,或者没有提供,则该候选者被认为是兼容的。

  2. 如果只有一个候选者被认为是兼容的,那么该候选者获胜。

  3. 如果多个候选者是兼容的,但其中一个候选者与其他候选者匹配所有相同的属性,Gradle 会选择该候选者。这是具有“最长”匹配的候选者。

  4. 如果多个候选者是兼容的,并且与相同数量的属性兼容,Gradle 需要对候选者进行消歧。

    1. 对于每个请求的属性,如果候选者没有与消歧规则匹配的值,则将其从考虑范围中排除。

    2. 如果属性具有已知的优先级,Gradle 将在只有一个候选者剩余时停止。

    3. 如果属性没有已知的优先级,Gradle 必须考虑所有属性。

  5. 如果仍然存在多个候选者,Gradle 将开始考虑“额外”属性来对多个候选者进行消歧。额外属性是消费者没有请求但至少在一个候选者上存在的属性。这些额外属性按优先级顺序考虑。

    1. 如果属性具有已知的优先级,Gradle 将在只有一个候选者剩余时停止。

    2. 在考虑了所有具有优先级的额外属性之后,如果剩余的候选者与所有非排序的消歧规则兼容,则可以选择它们。

  6. 如果仍然存在多个候选者,Gradle 将再次考虑额外属性。如果候选者具有最少的额外属性数量,则可以选择它。

如果在任何步骤中都没有候选者保持兼容,则解析失败。此外,Gradle 会输出从步骤 1 开始的所有兼容候选者的列表,以帮助调试变体匹配失败。

插件和生态系统可以通过实现兼容性规则、消歧规则以及告诉 Gradle 属性的优先级来影响选择算法。具有更高优先级的属性用于按顺序消除兼容的匹配项。

例如,在 Java 生态系统中,org.gradle.usage 属性的优先级高于 org.gradle.libraryelements。这意味着,如果两个候选者都具有对 org.gradle.usageorg.gradle.libraryelements 的兼容值,Gradle 将选择通过 org.gradle.usage 的消歧规则的候选者。