マルチプロジェクトの基本

簡単なプログラムならば単一プロジェクトから作り始めてもいいが、ビルドが複数の小さいのサブプロジェクトに分かれていくのが普通だ。

ビルド内のサブプロジェクトは、それぞれ独自のソースディレクトリを持ち、packageBin を実行すると独自の JAR ファイルを生成するなど、概ね通常のプロジェクトと同様に動作する。

サブプロジェクトは、lazy val を用いて Project 型の値を宣言することで定義される。例えば:

scalaVersion := "3.7.3"
LocalRootProject / publish / skip := true

lazy val core = (project in file("core"))
  .settings(
    name := "core",
  )

lazy val util = (project in file("util"))
  .dependsOn(core)
  .settings(
    name := "util",
  )

val 定義された変数名はプロジェクトの ID 及びベースディレクトリの名前になる。ID は sbt シェルからプロジェクトを指定する時に用いられる。

sbt は必ずルートプロジェクトを定義するので、上の例のビルド定義は合計 3つのサブプロジェクトを持つ。

サブプロジェクト間依存性

あるサブプロジェクトを、他のサブプロジェクトにあるコードに依存させたい場合、dependsOn(...) を使ってこれを宣言する。例えば、utilcore のクラスパスが必要な場合は util の定義を次のように書く:

lazy val util = (project in file("util"))
  .dependsOn(core)

タスク集約

タスク集約は、集約する側のサブプロジェクトで任意のタスクを実行するとき、集約される側の複数のサブプロジェクトでも同じタスクが実行されるという関係を意味する。

scalaVersion := "3.7.3"

lazy val root = (project in file("."))
  .autoAggregate
  .settings(
    publish / skip := true
  )

lazy val util = (project in file("util"))

lazy val core = (project in file("core"))

上の例では、ルートプロジェクトが utilcore を集約する。そのため、sbt シェルに compile と打ち込むと、3つのサブプロジェクトが並列にコンパイルされる。

ルートプロジェクト

ビルドのルートにあるサブプロジェクトは、ルートプロジェクトと呼ばれ、ビルドの中で特別な役割を果たすことがある。もしルートディレクトリにサブプロジェクトが定義されてない場合、sbt は自動的に他のプロジェクトを集約するデフォルトのルートプロジェクトを生成する。

コモン・セッティング

sbt 2.x では、settings(...) を使わずに build.sbt にセッティングを直書きした場合、コモン・セッティングとして全サブプロジェクトに注入される。

scalaVersion := "3.7.3"

lazy val core = (project in file("core"))

lazy val app = (project in file("app"))
  .dependsOn(core)

上の例では、scalaVersion セッティングはデフォルトのルートプロジェクト、coreutil に適用される。

既にサブプロジェクトにスコープ付けされたセッティングはこのルールの例外となる。

scalaVersion := "3.7.3"

lazy val core = (project in file("core"))

lazy val app = (project in file("app"))
  .dependsOn(core)

// これは app のみに適用される
app / name := "app1"

この例外を利用して、以下のように、ルートプロジェクトにのみ適用されるセッティングを書くことができる:

scalaVersion := "3.7.3"

lazy val core = (project in file("core"))

lazy val app = (project in file("app"))
  .dependsOn(core)

// これらは root にのみ適用される
LocalRootProject / name := "root"
LocalRootProject / publish / skip := true