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

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

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

Gradle定义的标准属性

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

独立于生态系统的标准属性

表 1. 独立于生态系统的标准变体属性
属性名称 描述 价值观 兼容性和消歧规则

org.gradle.usage

表示变体的主要目的

Usage根据使用中定义的常量构建的值

遵循生态系统语义(例如java-runtime可以用来代替java-api但不能相反)

org.gradle.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 世界中,embedded与 兼容external

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的名称。

值是套件的名称。

无默认,无兼容性

org.gradle.testsuite.target.name

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

值是目标的名称。

无默认,无兼容性

org.gradle.testsuite.type

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

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

无默认,无兼容性

JVM 生态系统还包含许多针对不同属性的兼容性和消歧规则。愿意了解更多的读者可以看一下 的代码org.gradle.api.internal.artifacts.JavaEcosystemSupport

本地生态系统特定属性

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

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

org.gradle.native.debuggable

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

布尔值

不适用

org.gradle.native.optimized

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

布尔值

不适用

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

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,属性的值必须通过对象工厂创建:

Example 4. Named attributes
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.usage和的两个候选值都具有兼容的值org.gradle.libraryelements,Gradle 将选择通过 的消歧规则的候选者org.gradle.usage