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.sbt 和 build.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、插件和应用依赖的仓库可全局配置,并声明为覆盖构建或插件定义中配置的解析器。分为两部分:
- 定义 launcher 使用的仓库。
- 指定这些仓库应覆盖构建定义中的仓库。
可通过定义 ~/.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")
)
要排除依赖的某些传递依赖,使用 excludeAll 或 exclude 方法。当项目将发布 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 任务。默认情况下,这会解析具有 sources 或 javadoc 分类器的所有构件。通过配置 transitiveClassifiers 设置选择要获取的分类器。例如,仅获取源码:
transitiveClassifiers := Seq("sources")
下载源码
下载源码和 API 文档 jar 通常由 IDE 插件处理。这些插件使用 updateClassifiers 和 updateSbtClassifiers 任务,生成引用这些 jar 的 Update-Report。
要让 sbt 在不使用 IDE 插件的情况下下载依赖的源码,在依赖定义中添加 withSources()。对于 API jar,添加 withJavadoc()。例如:
libraryDependencies +=
("org.apache.felix" % "org.apache.felix.framework" % "1.8.0").withSources().withJavadoc()
注意此操作不具传递性。为此请使用 update*Classifiers 任务。