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"

如果您將本機 Maven 儲存庫新增為儲存庫,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 來覆寫啟動器使用的儲存庫,該檔案必須包含格式與 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,以將這些儲存庫用於依賴項目解析和擷取。

明確 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 方法。當要為專案發佈 pom 時,應該使用 exclude 方法。它需要排除的組織和模組名稱。例如,

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) 預設會驗證下載檔案的校驗碼。它也預設會發布 Artifact 的校驗碼。要使用的校驗碼由 checksums 設定指定。

在更新期間停用校驗碼檢查

update / checksums := Nil

在發布 Artifact 期間停用校驗碼建立

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 中的 scopes 類似。sbt 會根據定義它們的設定,將依賴項新增至不同的類別路徑。請參閱Maven Scopes 的說明,以了解詳細資訊。

您可以透過選取其一個或多個設定,以對應至您的專案的一個或多個設定,來將依賴項放入設定中。最常見的情況是讓您的某個設定 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" 的新設定,並將其設為專案私有的,以便不會用於發布。請參閱更新報告,以了解有關選取受管理 Artifact 的詳細資訊。

沒有對應 (沒有 "->") 的設定會對應到 "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 檔案中指定儲存庫。