簡而言之,名稱 sbt 不代表任何意義,它就只是「sbt」,而且應該這樣寫。
當 Mark Harrah (@harrah) 第一次建立專案時,他稱之為「Simple Build Tool」,但在他的第一次公開宣告中,他已經將其簡稱為「sbt」。隨著時間的推移,有些人將 sbt 重新定義為「Scala Build Tool」,但我們認為這也不準確,因為它可以用來建置僅限 Java 的專案。
現在我們只稱 sbt 為「sbt」,為了強調這個名稱不再是首字母縮略字,我們總是全部用小寫字母書寫。不過,我們對酢豚 (subuta) 這個暱稱感到很酷。
預設情況下,sbt 1.9.8 會隱藏大多數堆疊追蹤和偵錯資訊。它具有在畫面上減少雜訊的優點,但作為一個新手,它可能會讓您不知所措。若要查看較高詳細程度的指令先前輸出,請輸入 last <task>
,其中 <task>
是失敗的任務或您想要檢視詳細輸出的任務。例如,如果您發現您的 update
無法如預期載入所有依賴,您可以輸入
> last update
它將顯示上次執行 update
指令的完整輸出。
有時 sbt 無法偵測到不支援 ansi 程式碼,而且您會得到如下所示的輸出
[0m[ [0minfo [0m] [0mSet current project to root
或者支援 ansi 程式碼,但您想要停用彩色輸出。若要完全停用 ansi 程式碼,請傳遞 -no-colors
選項
$ sbt -no-colors
在 sbt 的 Shell 中執行 console
。
:=
、+=
和 ++=
方法是什麼? 這些是金鑰上用來建構 Setting
或 Task
的方法。《入門指南》涵蓋了所有這些方法,例如,請參閱.sbt 建置定義、任務圖和附加值。
%
方法是什麼? 它用於在指定管理的依賴時,從字串建立 ModuleID
。閱讀《入門指南》中關於函式庫依賴的內容。
ThisBuild / scalaVersion
的含義是什麼? ThisBuild
充當一個特殊的子專案名稱,您可以使用它來定義建置的預設值。當您定義一個或多個子專案,而且當子專案沒有定義 scalaVersion
金鑰時,它會尋找 ThisBuild / scalaVersion
。
請參閱建置範圍設定。
ModuleID
、Project
等是什麼? 若要找出未知的類型或方法,請查看入門指南 (如果您還沒看過)。也可以嘗試查看常用方法、值和類型的索引和API 文件。
依預設,成品中包含的檔案會由相關套件任務限定範圍的任務 mappings
設定。mappings
任務會傳回從要包含的檔案到 jar 內路徑的對應序列 Seq[(File,String)]
。請參閱對應檔案,以取得有關建立這些對應的詳細資訊。
例如,若要將產生的來源新增到封裝的來源成品
Compile / packageSrc / mappings ++= {
import Path.{flat, relativeTo}
val base = (Compile / sourceManaged).value
val srcs = (Compile / managedSources).value
srcs pair (relativeTo(base) | flat)
}
這會從 managedSources
任務取得來源,並根據 managedSource
基礎目錄使來源相對化,然後回退到扁平化的對應。如果來源產生任務沒有將來源寫入 managedSource
目錄,則必須調整對應函式,嘗試根據其他目錄進行相對化,或者對產生器使用更適當的處理方式。
請參閱產生檔案。
請參閱快取。
請參閱如何定義自訂依賴組態。
run
之外,我該如何建立自訂執行任務? 此答案摘錄自郵件清單討論。
請閱讀《入門指南》,直到自訂設定,以了解背景資訊。
基本執行任務是由下列程式碼建立的
lazy val myRunTask = taskKey[Unit]("A custom run task.")
// this can go either in a `build.sbt` or the settings member
// of a Project in a full configuration
fullRunTask(myRunTask, Test, "foo.Foo", "arg1", "arg2")
如果您希望能夠在命令列上提供引數,請將 TaskKey
取代為 InputKey
,並將 fullRunTask
取代為 fullRunInputTask
。Test
部分可以用另一個組態取代,例如 Compile
,以使用該組態的類別路徑。
此執行任務可以藉由在作用域中指定任務金鑰個別設定。例如
myRunTask / fork := true
myRunTask / javaOptions += "-Xmx6144m"
工具依賴用於實作任務,而且專案原始碼不需要這些依賴。這些依賴可以在其自身的組態和類別路徑中宣告。以下是步驟
舉例來說,考慮一個 proguard
任務。此任務需要 ProGuard jar 才能執行工具。首先,定義並新增新的組態
lazy val ProguardConfig = config("proguard").hide
ivyConfigurations += ProguardConfig
然後,
// Add proguard as a dependency in the custom configuration.
// This keeps it separate from project dependencies.
libraryDependencies +=
"net.sf.proguard" % "proguard" % "4.4" % ProguardConfig.name
// Extract the dependencies from the UpdateReport.
ProguardConfig / managedClasspath := {
// these are the types of artifacts to include
val artifactTypes: Set[String] = (ProguardConfig / classpathTypes).value
Classpaths.managedJars(proguardConfig, artifactTypes, update.value)
}
// Use the dependencies in a task, typically by putting them
// in a ClassLoader and reflectively calling an appropriate
// method.
proguard := {
val cp: Seq[File] = (ProguardConfig / managedClasspath).value
// ... do something with , which includes proguard ...
}
定義中繼類別路徑是選用的,但它對於偵錯或如果需要由多個任務使用,則可能會很有用。也可以內嵌指定成品類型。此替代的 proguard
任務看起來會像這樣
proguard := {
val artifactTypes = Set("jar")
val cp =
Classpaths.managedJars(proguardConfig, artifactTypes, update.value)
// ... do something with , which includes proguard ...
}
可以註冊額外的 JAR 檔,這些 JAR 檔會被放置在 sbt 的類別路徑 (classpath) 中。透過 State,可以取得一個 xsbti.ComponentProvider,它管理應用程式元件。元件是指 ~/.sbt/boot/
目錄中的檔案群組,在這個情況下,應用程式是 sbt。除了基礎的類別路徑外,「額外」元件中的元件也會被包含在 sbt 的類別路徑中。
(注意:應用程式類別路徑上的額外元件是在啟動器組態檔 boot.properties
的 [main]
區段中的 components
屬性所宣告的。)
因為這些元件會被新增到 ~/.sbt/boot/
目錄,而 ~/.sbt/boot/
目錄可能為唯讀,這可能會導致失敗。在這種情況下,使用者通常是故意這樣設定 sbt 的,因此通常不需要錯誤恢復(只需簡短的錯誤訊息說明情況即可)。
以下程式碼可用於需要 State => State
的地方,例如 onLoad
設定(如下所述)或 command 中。它會將一些檔案新增到「額外」元件中,如果這些檔案尚未新增,則會重新載入 sbt。請注意,重新載入會捨棄使用者的會話狀態。
def augment(extra: Seq[File])(s: State): State = {
// Get the component provider
val cs: xsbti.ComponentProvider = s.configuration.provider.components()
// Adds the files in 'extra' to the "extra" component
// under an exclusive machine-wide lock.
// The returned value is 'true' if files were actually copied and 'false'
// if the target files already exists (based on name only).
val copied: Boolean = s.locked(cs.lockFile, cs.addToComponent("extra", extra.toArray))
// If files were copied, reload so that we use the new classpath.
if(copied) s.reload else s
}
請參閱 如何在啟動時執行操作。
以下範例會維護專案載入次數的計數,並印出該數字。
{
// the key for the current count
val key = AttributeKey[Int]("loadCount")
// the State transformer
val f = (s: State) => {
val previous = s get key getOrElse 0
println("Project load count: " + previous)
s.put(key, previous + 1)
}
Global / onLoad := {
val previous = (Global / onLoad).value
f compose previous
}
}
設定初始化器會依序執行。如果某個設定的初始化依賴於尚未初始化的其他設定,sbt 將會停止載入。
在這個範例中,我們嘗試在 libraryDependencies
使用空序列初始化之前,將一個程式庫附加到其中。
libraryDependencies += "commons-io" % "commons-io" % "1.4" % "test"
disablePlugins(plugins.IvyPlugin)
要更正這個問題,請包含 IvyPlugin 外掛程式設定,其中包含 libraryDependencies := Seq()
。因此,我們只需刪除明確的停用設定。
libraryDependencies += "commons-io" % "commons-io" % "1.4" % "test"
當使用 作用域設定時,會發生更微妙的此錯誤變體。
// error: Reference to uninitialized setting
settings = Seq(
libraryDependencies += "commons-io" % "commons-io" % "1.2" % "test",
fullClasspath := fullClasspath.value.filterNot(_.data.name.contains("commons-io"))
)
此設定在測試和編譯作用域之間有所不同。解決方案是使用作用域設定,既作為初始化器的輸入,又作為我們更新的設定。
Compile / fullClasspath := (Compile / fullClasspath).value.filterNot(_.data.name.contains("commons-io"))
當發佈的校驗碼(例如 sha1 或 md5 雜湊值)與下載的成品(例如 jar 或 pom.xml)計算出的校驗碼不同時,就會發生此錯誤。這種錯誤的一個例子是
[warn] problem while downloading module descriptor:
https://repo1.maven.org/maven2/commons-fileupload/commons-fileupload/1.2.2/commons-fileupload-1.2.2.pom:
invalid sha1: expected=ad3fda4adc95eb0d061341228cc94845ddb9a6fe computed=0ce5d4a03b07c8b00ab60252e5cacdc708a4e6d8 (1070ms)
無效的校驗碼通常應報告給存放庫所有者(如上述錯誤的 處理方式)。同時,您可以使用以下設定暫時停用檢查
checksums in update := Nil
有關詳細資訊,請參閱 程式庫管理。
這個問題經常出現。外掛程式只會針對 sbt 使用的 Scala 版本(目前為 2.12)發佈。您仍然可以在交叉編譯期間使用外掛程式,因為 sbt 只會尋找 2.12 版本的外掛程式。
...除非您將外掛程式指定在錯誤的地方!
一個典型的錯誤是將全域外掛程式定義放在 ~/.sbt/plugins.sbt
中。這是錯誤的。 ~/.sbt
中的 .sbt
檔案會針對每個建置載入,也就是針對每個交叉編譯載入。因此,如果您針對 Scala 2.11.0 建置,sbt 會嘗試尋找針對 2.11.0 編譯的外掛程式版本,而且通常找不到。那是因為它不知道相依性是外掛程式。
若要告知 sbt 相依性是 sbt 外掛程式,請確保您將全域外掛程式定義在 ~/.sbt/plugins/
中的 .sbt
檔案中。sbt 知道 ~/.sbt/plugins
中的檔案僅供 sbt 本身使用,而不是作為一般建置定義的一部分。如果您在該目錄下的檔案中定義外掛程式,它們就不會妨礙您的交叉編譯。任何以 .sbt
結尾的檔名都可以,但大多數人使用 ~/.sbt/plugins/build.sbt
或 ~/.sbt/plugins/plugins.sbt
。
請參閱 社群外掛程式,以取得目前可用的外掛程式列表。