クロスビルドの設定
このページではクロスビルドの設定を説明する。概要はクロスビルドを読んでほしい。
クロスビルドされたライブラリの使用
複数の Scala バージョン向けにビルドされたライブラリを使用するには、ModuleID の最初の % を %% にする。これにより sbt はライブラリのビルドに使用中の Scala バージョンをライブラリ依存性のモジュール名に追加する。例:
libraryDependencies += "org.typelevel" %% "cats-effect" % "3.5.4"
これをほぼ等価の ModuleID に、特定の Scala に対して手で書き換えると以下のようになる:
libraryDependencies += "org.typelevel" % "cats-effect_3" % "3.5.4"
Scala 3 専用のクロスバージョン
Scala 3 でアプリケーションを開発している場合、Scala 2.13 のライブラリを使用できる:
("a" % "b" % "1.0").cross(CrossVersion.for3Use2_13)
%% を使用するのと等価だが、scalaVersion が 3.x.y のときにライブラリの _2.13 バリアントに解決する点が異なる。
逆に、scalaVersion が 2.13.x のときにライブラリの _3 バリアントを使用するには CrossVersion.for2_13Use3 がある:
("a" % "b" % "1.0").cross(CrossVersion.for2_13Use3)
ライブラリ作者への警告: Scala 2.13 ライブラリに依存する Scala 3 ライブラリ、またはその逆を公開するのは一般的に安全ではない。エンドユーザーのクラスパスに scala-xml_2.13 と scala-xml_3 のように同じライブラリの 2 バージョンが混在する可能性がある。
クロスビルドされたライブラリの使用について(詳細)
ModuleID の cross メソッドを使うと、異なる Scala バージョンに対する動作を細かく制御できる。以下は等価である:
"a" % "b" % "1.0"
("a" % "b" % "1.0").cross(CrossVersion.disabled)
以下も等価である:
"a" %% "b" % "1.0"
("a" % "b" % "1.0").cross(CrossVersion.binary)
Scala のバイナリバージョンではなくフルバージョンを常に使用するようにデフォルトをオーバーライドする:
("a" % "b" % "1.0").cross(CrossVersion.full)
CrossVersion.patch は CrossVersion.binary と CrossVersion.full の中間的存在で、末尾の -bin-... サフィックスを削除して、バイナリ互換な Scala ツールチェーンの開発版をサポートする。
("a" % "b" % "1.0").cross(CrossVersion.patch)
CrossVersion.constant は固定値を指定する:
("a" % "b" % "1.0").cross(CrossVersion.constant("2.9.1"))
以下と等価である:
"a" % "b_2.9.1" % "1.0"
Project matrix
sbt 2.x では project matrix が導入され、クロスビルドをサブプロジェクトとして表すことで、並列実行できるようになった。
lazy val scala3 = "3.8.3"
lazy val scala2_13 = "2.13.18"
organization := "com.example"
scalaVersion := scala3
version := "0.1.0-SNAPSHOT"
lazy val core = (projectMatrix in file("core"))
.settings(
name := "core",
)
.jvmPlatform(scalaVersions = Seq(scala3, scala2_13))
.nativePlatform(scalaVersions = Seq(scala3, scala2_13))
// .jsPlatform(scalaVersions = Seq(scala3))
// optional
lazy val core3 = core.jvm(scala3)
lazy val coreNative3 = core.native(scala3)
サプブロジェクトの生成
読み込み時に project matrix は、プラットフォームと Scala バージョンの組み合わせをサブプロジェクトへと展開する。
sbt:cross-root> projects
[info] core
[info] core2_13
[info] coreNative
[info] coreNative2_13
[info] * cross-root
規約により、マトリックス中の JVM Scala 3 バリアントは、coreのように接尾辞を持たない名前が与えられる。
sbt:cross-root> core/run
[info] running (fork) example.main
Hello
[success] ok
build.sbt 内で、サブプロジェクトを参照するには、jvm(...)、js(...), もしくは native(...) を呼ぶことができる:
// For Scala
lazy val core3 = core.jvm(scalaVersion = scala3)
// For Java
lazy val intf0 = intf.jvm(autoScalaLibrary = false)
Virtual axis
マトリックスの各組み合わせは ProjectRow と呼ばれ、ProjectRow は、VirtualAxis の列によって構成されている。
final class ProjectRow(
val autoScalaLibrary: Boolean,
val axisValues: Seq[VirtualAxis],
val process: Project => Project
)
object VirtualAxis:
/**
* WeakAxis allows a row to depend on another row with Zero value.
* For example, Scala version can be Zero for Java project, and it's ok.
*/
abstract class WeakAxis extends VirtualAxis
/** StrongAxis requires a row to depend on another row with the same selected value. */
abstract class StrongAxis extends VirtualAxis
end VirtualAxis
VirtualAxis はさらに、WeakAxis と StrongAxis に分岐する。Scala バージョンは、弱い軸の例で、ある Scala バージョンを持つ列は、Scala バージョンを持たない Java の列に依存することができる。一方、同一のプラットフォーム間でしか依存することができないため、プラットフォームは強い軸として定義される。
例えば、SparkAxis は以下のように定義できる:
import sbt.*
case class SparkAxis(idSuffix: String, directorySuffix: String)
extends VirtualAxis.WeakAxis
具体的な SparkAxis の使用方法に関しては VirtualAxis に対するクロスビルドのレシピ参照。
公開規約
ライブラリのコンパイルに使用した Scala のバージョンを示すため、Scala ABI(アプリケーションバイナリインターフェース)バージョンをサフィックスとして使用する。例えば、アーティファクト名 cats-effect_2.13 は Scala 2.13.x が使用されたことを意味し、cats-effect_3 は Scala 3.x が使用されたことを意味する。このシンプルな方式で Maven、Ant などのビルドツールユーザーとの相互運用が可能である。2.13.0-RC1 のようなプレリリース版の Scala では、フルバージョンが ABI バージョンとして扱われる。
crossVersion セッティングで公開規約をオーバーライドできる:
CrossVersion.disabled(サフィックスなし)CrossVersion.binary(_<scala-abi-version>)CrossVersion.full(_<scala-version>)
デフォルト値は crossPaths に応じて CrossVersion.binary または CrossVersion.disabled に設定される。ただし、Scala 標準ライブラリと異なり Scala コンパイラはパッチリリース間で前方互換性がないため、コンパイラプラグインは CrossVersion.full を採用することが推奨される。