此頁面描述 sbt 建構定義,包括一些「理論」和 build.sbt
的語法。它假設您已安裝最新版本的 sbt,例如 sbt 1.9.8,知道如何使用 sbt,並且已閱讀「入門指南」中的前幾頁。
此頁面討論 build.sbt
建構定義。
在建構定義中,您將指定建構使用的 sbt 版本。這允許具有不同 sbt 啟動器版本的人員以一致的結果建構相同的專案。為此,請建立一個名為 project/build.properties
的檔案,其中指定 sbt 版本如下
sbt.version=1.9.8
如果本機沒有可用的必要版本,sbt
啟動器會為您下載。如果沒有此檔案,sbt
啟動器將選擇任意版本,這是不建議的,因為它會使您的建構無法移植。
建構定義在 build.sbt
中定義,它由一組專案(類型為 Project
)組成。由於術語 專案 可能含糊不清,我們在本指南中經常將其稱為 子專案。
例如,在 build.sbt
中,您可以像這樣定義位於目前目錄中的子專案
lazy val root = (project in file("."))
.settings(
name := "Hello",
scalaVersion := "2.12.7"
)
每個子專案都由鍵值對組態。
例如,一個鍵是 name
,它對應到一個字串值,即您的子專案的名稱。鍵值對列在 .settings(...)
方法下,如下所示
lazy val root = (project in file("."))
.settings(
name := "Hello",
scalaVersion := "2.12.7"
)
build.sbt
定義子專案,其中包含一系列稱為設定運算式的鍵值對,使用 build.sbt 特定領域語言(DSL)。
ThisBuild / organization := "com.example"
ThisBuild / scalaVersion := "2.12.18"
ThisBuild / version := "0.1.0-SNAPSHOT"
lazy val root = (project in file("."))
.settings(
name := "hello"
)
讓我們仔細看看 build.sbt
DSL:
每個項目都稱為設定運算式。其中一些項目也稱為任務運算式。我們將在本頁稍後詳細介紹其差異。
設定運算式包含三個部分
:=
在左側,name
、version
和 scalaVersion
是鍵。鍵是 SettingKey[T]
、TaskKey[T]
或 InputKey[T]
的實例,其中 T
是預期的值類型。鍵的種類說明如下。
由於鍵 name
的類型為 SettingKey[String]
,因此 name
上的 :=
運算子也特定類型為 String
。如果您使用錯誤的值類型,則建構定義將無法編譯
lazy val root = (project in file("."))
.settings(
name := 42 // will not compile
)
build.sbt
也可能散佈著 val
、lazy val
和 def
。在 build.sbt
中不允許使用最上層的 object
和 class
。它們應作為 Scala 原始檔放在 project/
目錄中。
鍵有三種形式
SettingKey[T]
:僅評估一次的值的鍵(值在載入子專案時計算,並保留)。TaskKey[T]
:值的鍵,稱為任務,每次引用時都會評估(類似於 scala 函數),可能會產生副作用。InputKey[T]
:以命令列引數作為輸入的任務的鍵。查看 輸入任務 以了解更多詳細資訊。內建鍵只是名為 Keys 的物件中的欄位。 build.sbt
隱式具有 import sbt.Keys._
,因此 sbt.Keys.name
可以稱為 name
。
可以使用各自的建立方法來定義自訂鍵:settingKey
、taskKey
和 inputKey
。每個方法都期望與鍵相關聯的值的類型以及描述。鍵的名稱取自指派給該鍵的 val
。例如,若要為名為 hello
的新任務定義鍵,
lazy val hello = taskKey[Unit]("An example task")
在此,我們使用了 .sbt
檔案除了設定外還可以包含 val
和 def
的事實。所有這些定義都會在設定之前進行評估,無論它們在檔案中的定義位置。
注意:通常,使用 lazy val 而不是 val 來避免初始化順序問題。
TaskKey[T]
據說定義了任務。任務是諸如 compile
或 package
之類的操作。它們可能會傳回 Unit
(Unit
是 Scala 的 void
),或者它們可能會傳回與任務相關的值,例如 package
是 TaskKey[File]
,並且其值是它建立的 jar 檔案。
每次您啟動任務執行時,例如在互動式 sbt 提示字元中鍵入 compile
,sbt 都會重新執行任何涉及的任務一次。
sbt 描述子專案的鍵值對可以為諸如名稱之類的設定保留固定的字串值,但它必須為諸如 compile
之類的任務保留一些可執行的程式碼 — 即使該可執行程式碼最終傳回字串,也必須每次都重新執行。
給定的鍵始終是指向任務或純粹設定。也就是說,「任務性」(是否每次重新執行)是鍵的屬性,而不是值。
目前在您的建構定義中存在的設定鍵清單可以透過在 sbt 提示字元中鍵入 settings
或 settings -v
來取得。
同樣,目前定義的任務鍵清單可以透過鍵入 tasks
或 tasks -v
來取得。您也可以查看命令列參考,以討論 sbt 提示字元中常用的內建任務。
如果符合以下條件,則鍵將列印在結果清單中
name
或 scalaVersion
)您也可以在 sbt 提示字元中鍵入 help <key>
以取得更多資訊。
使用 :=
,您可以將值指派給設定,將計算指派給任務。對於設定,值會在專案載入時計算一次。對於任務,每次執行任務時都會重新執行計算。
例如,若要實作上一節中的 hello
任務
lazy val hello = taskKey[Unit]("An example task")
lazy val root = (project in file("."))
.settings(
hello := { println("Hello!") }
)
當我們定義專案名稱時,已經看過定義設定的範例,
lazy val root = (project in file("."))
.settings(
name := "hello"
)
從型別系統的角度來看,從任務鍵建立的 Setting
與從設定鍵建立的 Setting
略有不同。taskKey := 42
會產生 Setting[Task[T]]
,而 settingKey := 42
會產生 Setting[T]
。在大多數情況下,這沒有區別;當任務執行時,任務鍵仍然會產生型別為 T
的值。
T
與 Task[T]
型別的差異有以下含義:設定不能依賴於任務,因為設定僅在專案載入時評估一次,且不會重新執行。關於這點,詳見任務圖。
在 sbt shell 中,您可以輸入任何任務的名稱來執行該任務。這就是為什麼輸入 compile
會執行 compile
任務的原因。compile
是一個任務鍵。
如果您輸入的是設定鍵的名稱而不是任務鍵的名稱,則會顯示設定鍵的值。輸入任務鍵的名稱會執行任務,但不會顯示結果值;若要查看任務的結果,請使用 show <任務名稱>
,而不是單純的 <任務名稱>
。鍵的命名慣例是使用 camelCase
,以便命令列名稱和 Scala 識別符號相同。
若要了解有關任何鍵的更多資訊,請在 sbt 互動式提示字元中輸入 inspect <鍵名稱>
。inspect
顯示的一些資訊可能還不明白,但在頂部它會顯示設定的值類型以及設定的簡短描述。
您可以將 import 語句放在 build.sbt
的頂部;它們不必以空行分隔。
有一些隱含的預設 import,如下所示
import sbt._
import Keys._
(此外,如果您有自動外掛程式,則會匯入標記在 autoImport
下的名稱。)
設定可以直接寫入 build.sbt
檔案,而不是將它們放在 .settings(...)
呼叫中。我們稱此為「裸樣式」。
ThisBuild / version := "1.0"
ThisBuild / scalaVersion := "2.12.18"
建議將此語法用於 ThisBuild
範圍的設定和新增外掛程式。請參閱後面的章節,了解有關範圍和外掛程式的資訊。
若要依賴第三方程式庫,有兩種選擇。第一種是將 jar 檔案放入 lib/
(非託管相依性),另一種是新增託管相依性,這在 build.sbt
中會如下所示
val derby = "org.apache.derby" % "derby" % "10.4.1.3"
ThisBuild / organization := "com.example"
ThisBuild / scalaVersion := "2.12.18"
ThisBuild / version := "0.1.0-SNAPSHOT"
lazy val root = (project in file("."))
.settings(
name := "Hello",
libraryDependencies += derby
)
這是在 Apache Derby 程式庫 10.4.1.3 版上新增託管相依性的方式。
libraryDependencies
鍵涉及兩個複雜性:+=
而不是 :=
,以及 %
方法。+=
會附加到鍵的舊值,而不是替換它,這在任務圖中有說明。%
方法用於從字串建構 Ivy 模組 ID,這在程式庫相依性中有說明。
我們將在「入門指南」稍後的內容中略過程式庫相依性的詳細資訊。稍後會有一整頁面涵蓋它。