Gradle 实际上如何选择以“-jvm”结尾的库?

cae*_*eus 3 jvm gradle maven kotlin

我正在从 Gradle 迁移到 Bazel。

\n

我在我的 gradle 中建立了testImplementationio.kotest:kotest-runner-junit5:5.4.2. 它工作完美。

\n

我向 Bazel 配置文件(WORKSPACE 和 BUILD)添加了相同的依赖项,但出现编译错误,就好像该库不存在一样。

\n

我去检查 Bazel 是否没有带来传递依赖,但它确实带来了。

\n

我检查了库的 POM,发现它没有依赖项。

\n

我在 Maven 中看到另一个名为io.kotest:kotest-runner-junit5-jvm:5.4.2.

\n

我用那个来代替。瞧\xc3\xa1,它起作用了!

\n

但为什么?Gradle 如何选择-jvm工件?

\n

aSe*_*emy 6

您的问题分为 3 个部分

  • Gradle 如何提供哪些变体?
  • Gradle 如何找到变体?
  • Gradle 如何确定如何选择正确的变体?

简短的回答是

  • Gradle 发布了一个附加的模块元数据文件,其中包含有关可用变体以及在哪里可以找到它们的信息。
  • Gradle 不仅仅使用 Mavengroup:artifact:version坐标来查找依赖项 - 它使用变体属性来“标记”可用模块和对模块的请求,因此它可以以非常细粒度的方式将请求的依赖项与可用的依赖项进行匹配。

Kotlin 多平台变体

Kotlin 多平台库发布了多个工件:一个“通用”发布的工件,以及它所针对的每个平台的变体。

因为io.kotest:kotest-runner-junit5这意味着有

通常,依赖关系由 Maven POM 和文件确定maven-metadata.xml。这就是巴泽尔正在做的事情。使用Maven的项目也是如此。那么 Gradle 如何确定可用的变体以及使用哪些变体呢?

变体可用性:Gradle 模块元数据

Gradle 发布了一个额外的元数据文件。https://docs.gradle.org/current/userguide/publishing_gradle_module_metadata.htm。它就像pom.xml,但包含更多信息。扩展名是.module,但内容是 JSON。

查看https://repo1.maven.org/maven2/io/kotest/kotest-runner-junit5/5.4.2/,我们可以看到该文件。

Maven Central 中的 kotest-runner-junit5-jvm 依赖项列表,突出显示文件“kotest-runner-junit5-5.4.2.module”

因为是JSON,所以我们可以查看里面。有一些元数据

{
  "formatVersion": "1.1",
  "component": {
    "group": "io.kotest",
    "module": "kotest-runner-junit5",
    "version": "5.4.2",
    "attributes": {
      "org.gradle.status": "release"
    }
  },
  ...
Run Code Online (Sandbox Code Playgroud)

还有一个variants数组。其中一个变体是-jvm变体,还有一个available-at.url,它是链接到 Maven 存储库中可用变体的相对路径。

   ...
  "variants": [
    ... 
    {
      "name": "jvmRuntimeElements-published",
      "attributes": {
        "org.gradle.category": "library",
        "org.gradle.libraryelements": "jar",
        "org.gradle.usage": "java-runtime",
        "org.jetbrains.kotlin.platform.type": "jvm"
      },
      "available-at": {
        "url": "../../kotest-runner-junit5-jvm/5.4.2/kotest-runner-junit5-jvm-5.4.2.module",
        "group": "io.kotest",
        "module": "kotest-runner-junit5-jvm",
        "version": "5.4.2"
      }
    }
    ... 
  ]
}
Run Code Online (Sandbox Code Playgroud)

这就是 Gradle发现可用变体的方式。

变体选择:属性匹配

该模块中实际上有多个变体,如果启用更多 Kotlin 多平台目标,还会有更多变体,因此最后一个问题是“Gradle 如何确定需要什么变体?”

答案来自"attributes"与变体相关的。它们只是 Gradle 用于匹配所需内容和可用内容的键值字符串。

https://docs.gradle.org/current/userguide/variant_attributes.html#attribute_matching

属性可能会说

我想要 org.company:some-artifact:1.0.0 的 Java 8 JAR

或者

我想要 io.kotest:something:2.0.0 的 Kotlin Native 1.7.0 源文件

它们只是键值字符串,所以它们可以是任何东西。我创建了用于共享 TypeScript 文件或 JaCoCo XML 报告文件的属性。

为什么我们在编写Gradle文件时永远看不到这些属性?

当您在 Gradle 中添加依赖项时

// build.gradle.kts
plugins {
  kotlin("jvm") version "1.7.20"
}

dependencies {
  testImplementation("io.kotest:kotest-runner-junit5:5.4.2")
}
Run Code Online (Sandbox Code Playgroud)

没有属性啊 那么 Gradle 如何知道选择-jvm变体呢?

Gradle 看到您已经使用 添加了一个依赖项testImplementation,它是一个Configuration

(旁白:我认为“配置”这个名字很令人困惑。它不是项目行为方式的配置。我更喜欢把它想象成一组海军战舰可能有一个用于战斗的“配置”,或者一个“配置”用于加载耗材。更多的是关于“形状”,而不是控制 Gradle 属性或操作。)

定义配置后,它们也会被标记为属性,Gradle 将使用这些属性在“kotest-runner-junit5”的请求和它在注册存储库中发现的内容之间扮演匹配者的角色

在 的情况下testImplementation("io.kotest:kotest-runner-junit5:5.4.2"),Gradle 可以看到它testImplementation具有“我需要 JVM 变体”的属性,并且它可以使用 Maven Central 中的模块元数据来查找匹配的依赖项。