此頁面介紹單一建置中的多個子專案。
請先閱讀入門指南中的先前頁面,尤其是您需要了解build.sbt,然後再閱讀此頁面。
將多個相關子專案保留在單一建置中可能很有用,尤其是在它們彼此依賴並且您傾向於一起修改它們的情況下。
建置中的每個子專案都有自己的來源目錄,在您執行封裝時會產生自己的 jar 檔案,並且通常像任何其他專案一樣運作。
專案是透過宣告類型為 Project 的 lazy val 來定義。例如,
lazy val util = (project in file("util"))
lazy val core = (project in file("core"))
val 的名稱用作子專案的 ID,用於在 sbt shell 中參考子專案。
如果基本目錄與 val 的名稱相同,則可以選擇省略基本目錄。
lazy val util = project
lazy val core = project
若要將多個子專案的通用設定分解出來,請定義範圍設定為 ThisBuild
。ThisBuild
作為一個特殊的子專案名稱,您可以使用它來定義建置的預設值。當您定義一個或多個子專案時,如果子專案未定義 scalaVersion
金鑰,它將會尋找 ThisBuild / scalaVersion
。
限制是右側必須是一個純值或範圍設定為 Global
或 ThisBuild
的設定,而且沒有範圍設定為子專案的預設設定。(請參閱範圍)
ThisBuild / organization := "com.example"
ThisBuild / version := "0.1.0-SNAPSHOT"
ThisBuild / scalaVersion := "2.12.18"
lazy val core = (project in file("core"))
.settings(
// other settings
)
lazy val util = (project in file("util"))
.settings(
// other settings
)
現在我們可以將 version
提升到一個位置,並且當您重新載入建置時,它將反映在所有子專案中。
將多個專案的通用設定分解出來的另一種方式是建立一個名為 commonSettings
的序列,並在每個專案上呼叫 settings
方法。
lazy val commonSettings = Seq(
target := { baseDirectory.value / "target2" }
)
lazy val core = (project in file("core"))
.settings(
commonSettings,
// other settings
)
lazy val util = (project in file("util"))
.settings(
commonSettings,
// other settings
)
建置中的專案可以完全彼此獨立,但通常它們會因某種依賴關係而彼此相關。依賴關係有兩種:彙總和類別路徑。
彙總表示在彙總專案上執行任務也會在彙總的專案上執行。例如,
lazy val root = (project in file("."))
.aggregate(util, core)
lazy val util = (project in file("util"))
lazy val core = (project in file("core"))
在以上範例中,根專案會彙總 util
和 core
。使用範例中的兩個子專案啟動 sbt,然後嘗試編譯。您應該會看到所有三個專案都已編譯。
在執行彙總的專案中 (在此案例中為根專案),您可以控制每個任務的彙總。例如,若要避免彙總 update
任務
lazy val root = (project in file("."))
.aggregate(util, core)
.settings(
update / aggregate := false
)
[...]
update / aggregate
是範圍設定為 update
任務的彙總金鑰。(請參閱範圍。)
注意:彙總將以平行方式執行彙總的任務,且它們之間沒有定義的順序。
專案可能依賴另一個專案中的程式碼。這可以透過新增 dependsOn
方法呼叫來完成。例如,如果 core 需要類別路徑上的 util,您會將 core 定義為
lazy val core = project.dependsOn(util)
現在 core
中的程式碼可以使用 util
中的類別。這也會在編譯專案時建立專案之間的順序;util
必須在編譯 core 之前更新和編譯。
若要依賴多個專案,請使用 dependsOn
的多個引數,例如 dependsOn(bar, baz)
。
core dependsOn(util)
表示 core
中的 compile
組態依賴 util
中的 compile
組態。您可以將此明確寫為 dependsOn(util % "compile->compile")
。
"compile->compile"
中的 ->
表示「依賴於」,因此 "test->compile"
表示 core
中的 test
組態會依賴 util
中的 compile
組態。
省略 ->config
部分表示 ->compile
,因此 dependsOn(util % "test")
表示 core
中的 test
組態依賴 util
中的 Compile
組態。
一個有用的宣告是 "test->test"
,表示 test
依賴於 test
。這可讓您將測試的公用程式碼放置在 util/src/test/scala
中,然後在 core/src/test/scala
中使用該程式碼,例如。
您可以為依賴項設定多個組態,並以分號分隔。例如,dependsOn(util % "test->test;compile->compile")
。
在具有許多檔案和許多子專案的極大型專案中,sbt 在持續監視已變更的檔案時,效能可能會較差,並且會使用大量的磁碟和系統 I/O。
sbt 具有 trackInternalDependencies
和 exportToInternal
設定。這些可用於控制當您呼叫 compile
時,是否要觸發相依子專案的編譯。這兩個金鑰都將採用三個值之一:TrackLevel.NoTracking
、TrackLevel.TrackIfMissing
和 TrackLevel.TrackAlways
。預設情況下,它們都設定為 TrackLevel.TrackAlways
。
當 trackInternalDependencies
設定為 TrackLevel.TrackIfMissing
時,sbt 將不再嘗試自動編譯內部 (專案間) 依賴項,除非輸出目錄中沒有 *.class
檔案 (或當 exportJars
為 true
時的 JAR 檔案)。
當設定設定為 TrackLevel.NoTracking
時,將會略過內部依賴項的編譯。請注意,仍然會附加類別路徑,而且依賴圖仍然會將它們顯示為依賴項。這樣做的動機是為了在開發期間儲存具有許多子專案的建置中,檢查變更的 I/O 負荷。以下說明如何將所有子專案設定為 TrackIfMissing
。
ThisBuild / trackInternalDependencies := TrackLevel.TrackIfMissing
ThisBuild / exportJars := true
lazy val root = (project in file("."))
.aggregate(....)
exportToInternal
設定可讓依賴方子專案選擇不使用內部追蹤,如果您想要追蹤大多數子專案,但少數除外,這可能會很有用。trackInternalDependencies
和 exportToInternal
設定的交集將用於判斷實際追蹤層級。以下範例說明如何選擇不使用一個專案
lazy val dontTrackMe = (project in file("dontTrackMe"))
.settings(
exportToInternal := TrackLevel.NoTracking
)
如果沒有為建置中的根目錄定義專案,sbt 會建立一個預設的專案,該專案會彙總建置中的所有其他專案。
因為專案 hello-foo
是使用 base = file("foo")
定義的,所以它將會包含在子目錄 foo 中。它的來源可以直接放在 foo
下方,例如 foo/Foo.scala
,或在 foo/src/main/scala
中。一般的 sbt 目錄結構 適用於 foo
下方,但建置定義檔案除外。
在 sbt 互動式提示中,輸入 projects
以列出您的專案,並輸入 project <projectname>
以選取目前的專案。當您執行像是 compile
的任務時,它會在目前的專案上執行。因此,您不一定必須編譯根專案,您可以只編譯一個子專案。
您可以透過明確指定專案 ID (例如 subProjectID/compile
) 來在另一個專案中執行任務。
.sbt
檔案中的定義在其他 .sbt
檔案中不可見。若要在 .sbt
檔案之間共用程式碼,請在建置根目錄的 project/
目錄中定義一個或多個 Scala 檔案。
如需詳細資訊,請參閱組織建置。
foo
中的任何 .sbt
檔案 (例如 foo/build.sbt
) 都會與整個建置的建置定義合併,但範圍限定為 hello-foo
專案。
如果您的整個專案都在 hello 中,請嘗試在 hello/build.sbt
、hello/foo/build.sbt
和 hello/bar/build.sbt
中定義不同的版本 (version := "0.6"
)。現在在 sbt 互動式提示中 show version
。您應該會得到類似以下的結果 (使用您定義的任何版本)
> show version
[info] hello-foo/*:version
[info] 0.7
[info] hello-bar/*:version
[info] 0.9
[info] hello/*:version
[info] 0.5
hello-foo/*:version
定義在 hello/foo/build.sbt
中,hello-bar/*:version
定義在 hello/bar/build.sbt
中,而 hello/*:version
則定義在 hello/build.sbt
中。請記住有作用域的鍵的語法。每個 version
鍵都會根據 build.sbt
的位置而作用於特定的專案。但是,這三個 build.sbt
都是同一個建置定義的一部分。
風格選擇
*.sbt
檔案中,而根目錄的 build.sbt
則只宣告最少的專案宣告,形式為 lazy val foo = (project in file("foo"))
,不包含設定。build.sbt
檔案中,以便將所有建置定義放在單一檔案中。然而,這取決於您的選擇。注意:您不能在子專案中擁有專案子目錄或 project/*.scala
檔案。foo/project/Build.scala
將會被忽略。