sbt update

有关基础介绍,请参阅入门指南中的库依赖基础

概要

sbt [query / ] update

描述

sbt 使用 Coursier 实现库管理,在其他生态系统中也称为包管理器。库管理的一般思路是,您可以在子项目中指定要使用的外部库,库管理系统将:

  • 检查所列仓库中是否存在这些版本
  • 查找传递依赖(即库所依赖的库)
  • 尝试解决版本冲突(如有)
  • 从仓库下载构件(如 JAR 文件)

依赖关系

声明依赖关系看起来像:

libraryDependencies += groupID %% artifactID % revision

libraryDependencies += groupID %% artifactID % revision % configuration

此外,可以一起声明多个依赖:

libraryDependencies ++= Seq(
  groupID %% artifactID % revision,
  groupID %% otherID % otherRevision
)

若您使用的依赖是用 sbt 构建的,请将第一个 % 改为 %%

libraryDependencies += groupID %% artifactID % revision

这将使用与您当前 Scala 版本匹配的依赖 JAR。若解析此类依赖时出错,该依赖可能未为您使用的 Scala 版本发布。详见交叉构建

versionScheme 与驱逐错误

sbt 允许库作者使用 versionScheme 设置声明版本语义:

// Semantic Versioning applied to 0.x, as well as 1.x, 2.x, etc
versionScheme := Some(VersionScheme.EarlySemVer)

当 Coursier 发现库的多个版本(例如 Cats Effect 2.x 和 Cats Effect 3.0.0-M4)时,通常通过从图中移除较旧版本来解决冲突。此过程俗称驱逐,如「Cats Effect 2.2.0 被驱逐」。

若新版本与 Cats Effect 2.2.0 二进制兼容,则可行。但本例中库作者已声明其 二进制兼容,因此该驱逐实际上不安全。不安全的驱逐会导致运行时问题,如 ClassNotFoundException。Coursier 本应解析失败。

lazy val use = project
  .settings(
    name := "use",
    libraryDependencies ++= Seq(
      "org.http4s" %% "http4s-blaze-server" % "0.21.11",
      "org.typelevel" %% "cats-effect" % "3.0.0-M4",
    ),
  )

sbt 在 Coursier 返回候选版本后执行此二次兼容性检查:

[error] stack trace is suppressed; run last use / update for the full output
[error] (use / update) found version conflict(s) in library dependencies; some are suspected to be binary incompatible:
[error]
[error]   * org.typelevel:cats-effect_2.12:3.0.0-M4 (early-semver) is selected over {2.2.0, 2.0.0, 2.0.0, 2.2.0}
[error]       +- use:use_2.12:0.1.0-SNAPSHOT                        (depends on 3.0.0-M4)
[error]       +- org.http4s:http4s-core_2.12:0.21.11                (depends on 2.2.0)
[error]       +- io.chrisdavenport:vault_2.12:2.0.0                 (depends on 2.0.0)
[error]       +- io.chrisdavenport:unique_2.12:2.0.0                (depends on 2.0.0)
[error]       +- co.fs2:fs2-core_2.12:2.4.5                         (depends on 2.2.0)
[error]
[error]
[error] this can be overridden using libraryDependencySchemes or evictionErrorLevel

此机制称为 驱逐错误

选择退出驱逐错误检查

若库作者已声明兼容性破坏,但您希望忽略严格检查(常用于 scala-xml),可在 project/plugins.sbtbuild.sbt 中编写:

libraryDependencySchemes += "org.scala-lang.modules" %% "scala-xml" % VersionScheme.Always

要忽略所有驱逐错误:

evictionErrorLevel := Level.Info

解析器

sbt 默认使用标准 Maven Central 仓库。使用以下形式声明额外仓库:

resolvers += name at location

例如:

libraryDependencies ++= Seq(
    "org.apache.derby" % "derby" % "10.4.1.3",
    "org.specs" % "specs" % "1.6.1"
)

resolvers += "Sonatype OSS Snapshots" at "https://oss.sonatype.org/content/repositories/snapshots"

若您将本地 Maven 仓库添加为仓库,sbt 可搜索该仓库:

resolvers += Resolver.mavenLocal

覆盖默认解析器

resolvers 配置额外的内联用户解析器。默认情况下,sbt 将这些解析器与默认仓库(Maven Central 和本地 Ivy 仓库)组合形成 externalResolvers。要更精细控制仓库,直接设置 externalResolvers。若仅需在常规默认之外指定仓库,则配置 resolvers

例如,在默认仓库之外使用 Sonatype OSS Snapshots 仓库:

resolvers += "Sonatype OSS Snapshots" at "https://oss.sonatype.org/content/repositories/snapshots"

要使用本地仓库但不使用 Maven Central 仓库:

externalResolvers := Resolver.combineDefaultResolvers(resolvers.value.toVector, mavenCentral = false)

覆盖所有构建的解析器

用于获取 sbt、Scala、插件和应用依赖的仓库可全局配置,并声明为覆盖构建或插件定义中配置的解析器。分为两部分:

  1. 定义 launcher 使用的仓库。
  2. 指定这些仓库应覆盖构建定义中的仓库。

可通过定义 ~/.sbt/repositories 覆盖 launcher 使用的仓库,该文件必须包含与 Launcher 配置文件格式相同的 [repositories] 部分。例如:

[repositories]
local
my-maven-repo: https://example.org/repo
my-ivy-repo: https://example.org/ivy-repo/, [organization]/[module]/[revision]/[type]s/[artifact](-[classifier]).[ext]

可通过 sbt 启动脚本中的 sbt.repository.config 系统属性指定仓库文件的不同位置。最后一步是将 sbt.override.build.repos 设为 true,以使用这些仓库进行依赖解析和获取。

排除传递依赖

某些情况下需从所有依赖中排除传递依赖。可通过在 excludeDependencies 中设置 ExclusionRules 实现。

excludeDependencies ++= Seq(
  // commons-logging is replaced by jcl-over-slf4j
  ExclusionRule("commons-logging", "commons-logging")
)

要排除依赖的某些传递依赖,使用 excludeAllexclude 方法。当项目将发布 pom 时应使用 exclude 方法。需提供要排除的组织和模块名。例如:

libraryDependencies += 
  ("log4j" % "log4j" % "1.2.15").exclude("javax.jms", "jms")

显式 URL

若您的项目需要仓库中不存在的依赖,可按以下方式指定其 jar 的直接 URL:

libraryDependencies += "slinky" % "slinky" % "2.1" from "https://slinky2.googlecode.com/svn/artifacts/2.1/slinky.jar"

仅当通过配置的仓库无法找到依赖时,才将 URL 用作后备。此外,显式 URL 不包含在发布的元数据(即 pom 或 ivy.xml)中。

禁用传递性

默认情况下,这些声明会传递式获取所有项目依赖。某些情况下,您可能发现项目列出的依赖对其构建并非必需。例如,使用 Felix OSGI 框架的项目仅显式需要其主 jar 来编译和运行。使用 intransitive()notTransitive() 避免获取构件依赖,如下例:

libraryDependencies += ("org.apache.felix" % "org.apache.felix.framework" % "1.8.0").intransitive()

分类器

您可使用 classifier 方法为依赖指定分类器。例如,获取 TestNG 的 jdk15 版本:

libraryDependencies += ("org.testng" % "testng" % "5.7").classifier("jdk15")

对于多个分类器,使用多次 classifier 调用:

libraryDependencies += 
  "org.lwjgl.lwjgl" % "lwjgl-platform" % lwjglVersion classifier "natives-windows" classifier "natives-linux" classifier "natives-osx"

要传递式获取所有依赖的特定分类器,运行 updateClassifiers 任务。默认情况下,这会解析具有 sourcesjavadoc 分类器的所有构件。通过配置 transitiveClassifiers 设置选择要获取的分类器。例如,仅获取源码:

transitiveClassifiers := Seq("sources")

下载源码

下载源码和 API 文档 jar 通常由 IDE 插件处理。这些插件使用 updateClassifiersupdateSbtClassifiers 任务,生成引用这些 jar 的 Update-Report

要让 sbt 在不使用 IDE 插件的情况下下载依赖的源码,在依赖定义中添加 withSources()。对于 API jar,添加 withJavadoc()。例如:

libraryDependencies += 
  ("org.apache.felix" % "org.apache.felix.framework" % "1.8.0").withSources().withJavadoc()

注意此操作不具传递性。为此请使用 update*Classifiers 任务。