1. 库管理

库管理 

现在有一个关于库管理的入门页面,您可能想先阅读一下。

文档维护说明:最好消除此页面和入门页面之间的重叠,保留此页面更高级的主题,如校验和和外部 Ivy 文件。

简介 

您可以通过两种方式使用 sbt 管理库:手动或自动。这两种方式也可以混合使用。此页面将讨论这两种方法。此处显示的所有配置都是直接在.sbt 文件中设置的设置。

手动依赖管理 

手动管理依赖关系涉及将您要使用的任何 jar 文件复制到 lib 目录。sbt 将在编译、测试、运行和使用解释器时将这些 jar 文件放在类路径上。您负责添加、删除、更新以及以其他方式管理此目录中的 jar 文件。除非您想更改存储 jar 文件的目录的位置,否则无需对您的项目定义进行任何修改即可使用此方法。

要更改存储 jar 文件的目录,请更改项目定义中的 unmanagedBase 设置。例如,要使用 custom_lib/

unmanagedBase := baseDirectory.value / "custom_lib"

如果您想要更多控制和灵活性,请覆盖 unmanagedJars 任务,该任务最终会向 sbt 提供手动依赖项。默认实现大致如下

Compile / unmanagedJars := (baseDirectory.value ** "*.jar").classpath

如果您想除了默认目录之外还添加来自多个目录的 jar 文件,您可以这样做

Compile / unmanagedJars ++= {
    val base = baseDirectory.value
    val baseDirectories = (base / "libA") +++ (base / "b" / "lib") +++ (base / "libC")
    val customJars = (baseDirectories ** "*.jar") +++ (base / "d" / "my.jar")
    customJars.classpath
}

有关构建路径的更多信息,请参见路径

自动依赖管理 

这种依赖管理方法涉及指定项目的直接依赖关系,并让 sbt 处理依赖关系的检索和更新。

sbt 1.3.0+ 使用Coursier 来实现依赖管理。在 sbt 1.3.0 之前,sbt 使用了 Apache Ivy 十年。Coursier 在保持兼容性方面做得很好,但某些功能可能是 Apache Ivy 独有的。在这些情况下,您可以使用以下设置切换回 Ivy

ThisBuild / useCoursier := false

内联声明 

内联声明是指定要自动检索的依赖关系的基本方法。它们旨在作为使用 Ivy 进行完整配置的轻量级替代方案。

依赖关系 

声明依赖关系看起来像

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 版本发布。有关详细信息,请参见交叉构建

Ivy 可以根据您指定的约束条件选择模块的最新版本。而不是像 "1.6.1" 这样的固定版本,您指定 "latest.integration""2.9.+""[1.0,)"。有关详细信息,请参见Ivy 版本 文档。

解析器 

sbt 默认使用标准 Maven2 仓库。

使用以下形式声明其他仓库

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"

如果您将其添加为仓库,sbt 可以搜索您的本地 Maven 仓库

resolvers += "Local Maven Repository" at "file://"+Path.userHome.absolutePath+"/.m2/repository"

有关定义其他类型仓库的详细信息,请参见解析器

覆盖默认解析器 

resolvers 配置其他内联用户解析器。默认情况下,sbt 将这些解析器与默认仓库(Maven Central 和本地 Ivy 仓库)组合起来形成 externalResolvers。为了更好地控制仓库,请直接设置 externalResolvers。要仅指定除通常的默认仓库之外的仓库,请配置 resolvers

例如,要使用 Sonatype OSS 快照仓库作为默认仓库的补充,请使用

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. 定义启动器使用的仓库。
  2. 指定这些仓库应该覆盖构建定义中的那些仓库。

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

[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,以使用这些仓库进行依赖项解析和检索。

显式 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")
排除传递依赖关系 

要排除依赖项的某些传递依赖关系,请使用 excludeAllexclude 方法。exclude 方法应在为项目发布 pom 文件时使用。它需要要排除的组织和模块名称。例如,

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

excludeAll 方法更灵活,但由于它不能在 pom.xml 中表示,因此仅应在不需要生成 pom 文件时使用。例如,

libraryDependencies +=
  "log4j" % "log4j" % "1.2.15" excludeAll(
    ExclusionRule(organization = "com.sun.jdmk"),
    ExclusionRule(organization = "com.sun.jmx"),
    ExclusionRule(organization = "javax.jms")
  )

有关 API 详细信息,请参见ModuleID

在某些情况下,应该从所有依赖关系中排除传递依赖关系。这可以通过在 excludeDependencies 中设置 ExclusionRules 来实现。

excludeDependencies ++= Seq(
  // commons-logging is replaced by jcl-over-slf4j
  ExclusionRule("commons-logging", "commons-logging")
)
下载源代码 

下载源代码和 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 任务来实现这一点。

额外属性 

额外属性 可以通过向 extra 方法传递键值对来指定。

通过额外属性选择依赖项

libraryDependencies += "org" % "name" % "rev" extra("color" -> "blue")

在当前项目上定义额外属性

projectID := {
    val previous = projectID.value
    previous.extra("color" -> "blue", "component" -> "compiler-interface")
}
内联 Ivy XML 

sbt 额外支持直接在内联中指定 Ivy 配置文件的 configurations 或 dependencies 部分。您可以将其与内联 Scala 依赖项和仓库声明混合使用。

例如

ivyXML :=
  <dependencies>
    <dependency org="javax.mail" name="mail" rev="1.4.2">
      <exclude module="activation"/>
    </dependency>
  </dependencies>
Ivy 主目录 

默认情况下,sbt 使用标准的 Ivy 主目录位置 ${user.home}/.ivy2/。这可以通过设置 sbt 启动脚本中的系统属性 sbt.ivy.home 来在机器范围内配置,供 sbt 启动器和项目使用(在 设置 中描述)。

例如

java -Dsbt.ivy.home=/tmp/.ivy2/ ...
校验和 

sbt(通过 Ivy)默认情况下会验证下载文件的校验和。它还默认发布工件的校验和。要使用的校验和由 checksums 设置指定。

在更新期间禁用校验和检查

update / checksums := Nil

在发布工件期间禁用校验和创建

publishLocal / checksums := Nil

publish / checksums := Nil

默认值为

checksums := Seq("sha1", "md5")
冲突管理 

冲突管理器决定在依赖项解析引入相同库的不同版本时该怎么做。默认情况下,将选择最新的修订版。这可以通过设置 conflictManager 来更改,其类型为 ConflictManager。有关不同冲突管理器的详细信息,请参阅 Ivy 文档。例如,要指定不允许任何冲突,

conflictManager := ConflictManager.strict

设置此项后,任何冲突都会生成错误。要解决冲突,您必须配置依赖项覆盖,这将在后面的部分中解释。

驱逐警告 

以下直接依赖项将在 akka-actor 版本上引入冲突,因为 banana-rdf 需要 akka-actor 2.1.4。

libraryDependencies ++= Seq(
  "org.w3" %% "banana-rdf" % "0.4",
  "com.typesafe.akka" %% "akka-actor" % "2.3.7",
)

默认冲突管理器将选择 akka-actor 的较新版本 2.3.7。这可以在 show update 的输出中确认,它显示选择了较新版本,而较旧版本被驱逐。

> show update
[info] compile:

[info]  com.typesafe.akka:akka-actor_2.10
[info]    - 2.3.7
...
[info]    - 2.1.4
...
[info]      evicted: true
[info]      evictedReason: latest-revision
...
[info]      callers: org.w3:banana-rdf_2.10:0.4

此外,akka-actor 2.1.4 和 2.3.7 的二进制版本兼容性不能保证,因为第二段已向上调整。sbt 0.13.6+ 会自动检测到这一点并打印以下警告

[warn] There may be incompatibilities among your library dependencies.
[warn] Here are some of the libraries that were evicted:
[warn]  * com.typesafe.akka:akka-actor_2.10:2.1.4 -> 2.3.7
[warn] Run 'evicted' to see detailed eviction warnings

由于 akka-actor 2.1.4 和 2.3.7 不兼容二进制文件,因此解决此问题的唯一方法是将您的依赖项降级到 akka-actor 2.1.4,或者升级 banana-rdf 以使用 akka-actor 2.3。

覆盖版本 

对于二进制兼容的冲突,sbt 提供依赖项覆盖。它们使用 dependencyOverrides 设置进行配置,该设置是一组 ModuleIDs。例如,以下依赖项定义发生冲突,因为 spark 使用 log4j 1.2.16,而 scalaxb 使用 log4j 1.2.17

libraryDependencies ++= Seq(
   "org.spark-project" %% "spark-core" % "0.5.1",
   "org.scalaxb" %% "scalaxb" % "1.0.0"
)

默认冲突管理器选择 log4j 的最新修订版 1.2.17

> show update
[info] compile:
[info]    log4j:log4j:1.2.17: ...
...
[info]    (EVICTED) log4j:log4j:1.2.16
...

要更改所选版本,请添加覆盖

dependencyOverrides += "log4j" % "log4j" % "1.2.16"

这不会添加对 log4j 的直接依赖项,但会强制修订版为 1.2.16。这通过 show update 的输出得到确认

> show update
[info] compile:
[info]    log4j:log4j:1.2.16
...

注意:这只是一个 Ivy 功能,不会包含在已发布的 pom.xml 中。

未解析的依赖项错误 

在您的项目中添加以下依赖项会导致 vpp 2.2.1 的未解析的依赖项错误

libraryDependencies += "org.apache.cayenne.plugins" % "maven-cayenne-plugin" % "3.0.2"

sbt 0.13.6+ 将尝试在无法解析托管依赖项时重建依赖项树。这是一个近似值,但它应该有助于您找出问题依赖项的来源。在可能的情况下,sbt 将在模块旁边显示源位置

[warn]  ::::::::::::::::::::::::::::::::::::::::::::::
[warn]  ::          UNRESOLVED DEPENDENCIES         ::
[warn]  ::::::::::::::::::::::::::::::::::::::::::::::
[warn]  :: foundrylogic.vpp#vpp;2.2.1: not found
[warn]  ::::::::::::::::::::::::::::::::::::::::::::::
[warn] 
[warn]  Note: Unresolved dependencies path:
[warn]      foundrylogic.vpp:vpp:2.2.1
[warn]        +- org.apache.cayenne:cayenne-tools:3.0.2
[warn]        +- org.apache.cayenne.plugins:maven-cayenne-plugin:3.0.2 (/foo/some-test/build.sbt#L28)
[warn]        +- d:d_2.10:0.1-SNAPSHOT
缓存的解析 

有关性能改进选项,请参阅 缓存的解析

发布 

有关如何发布项目的说明,请参阅 发布

配置 

当您需要自定义的依赖项组(例如,用于插件)时,Ivy 配置是构建的有用功能。Ivy 配置本质上是依赖项的命名集。您可以阅读 Ivy 文档 以获取详细信息。

sbt 中对配置的内置使用类似于 Maven 中的范围。sbt 通过定义它们的配置将依赖项添加到不同的类路径。有关详细信息,请参阅 Maven 范围 的说明。

您可以通过选择一个或多个依赖项配置映射到一个或多个项目的配置,将依赖项放入配置中。最常见的情况是让您项目的配置 A 使用依赖项的配置 B。这种映射看起来像 "A->B"。要将此映射应用于依赖项,请将其添加到依赖项定义的末尾

libraryDependencies += "org.scalatest" %% "scalatest" % "3.2.17" % "test->compile"

这表示项目的 "test" 配置使用 ScalaTest"compile" 配置。有关更高级的映射,请参阅 Ivy 文档。发布到 Maven 仓库的大多数项目将使用 "compile" 配置。

配置的一个有用应用是将未用于普通类路径的依赖项分组。例如,您的项目可能使用 "js" 配置来自动下载 jQuery,然后通过修改 resources 将其包含在您的 jar 中。例如

val JS = config("js") hide

ivyConfigurations += JS

libraryDependencies += "jquery" % "jquery" % "3.2.1" % "js->default" from "https://code.jquery.com/jquery-3.2.1.min.js"

Compile / resources ++= update.value.select(configurationFilter("js"))

config 方法定义一个名为 "js" 的新配置,并将其设为对项目的私有配置,以便它不用于发布。有关选择托管工件的更多信息,请参阅 更新报告

没有映射(没有 "->")的配置将映射到 "default""compile"-> 仅在映射到与这些配置不同的配置时才需要。上面的 ScalaTest 依赖项可以简化为

libraryDependencies += "org.scalatest" %% "scalatest" % "3.2.17" % "test"
强制修订版(不推荐) 

注意:强制会导致逻辑不一致,因此不再推荐。

要声明我们更喜欢指定的版本而不是来自间接依赖项的版本,请使用 force()

libraryDependencies ++= Seq(
  "org.spark-project" %% "spark-core" % "0.5.1",
  "log4j" % "log4j" % "1.2.14" force()
)

注意:这只是一个 Ivy 功能,不能包含在已发布的 pom.xml 中。

已知限制 

Maven 支持依赖于 Coursier 或 Ivy 对 Maven POM 的支持。此支持的已知问题

  • 在 POM 的 parent 部分中指定 relativePath 将产生错误。
  • Ivy 会忽略 POM 中指定的仓库。解决方法是在内联或 Ivy ivysettings.xml 文件中指定仓库。