Cross-platform compilation support for sbt.
Requirements:
- sbt 1.2.1+
- For
JSPlatform: Scala.js 0.6.23+ or 1.0.0+ - For
NativePlatform: Scala Native 0.3.7+
If you are still using sbt 0.13.x, you must use sbt-crossproject v0.6.1 instead of v1.3.2.
In project/plugins.sbt:
addSbtPlugin("org.portable-scala" % "sbt-scalajs-crossproject" % "1.3.2")
addSbtPlugin("org.portable-scala" % "sbt-scala-native-crossproject" % "1.3.2")
addSbtPlugin("org.scala-js" % "sbt-scalajs" % "1.16.0")
addSbtPlugin("org.scala-native" % "sbt-scala-native" % "0.5.4")In build.sbt:
// If you are using Scala.js 0.6.x, you need the following import:
//import sbtcrossproject.CrossPlugin.autoImport.{crossProject, CrossType}
val sharedSettings = Seq(scalaVersion := "2.13.14")
lazy val bar =
// select supported platforms
crossProject(JSPlatform, JVMPlatform, NativePlatform)
.crossType(CrossType.Pure) // [Pure, Full, Dummy], default: CrossType.Full
.settings(sharedSettings)
.jsSettings(/* ... */) // defined in sbt-scalajs-crossproject
.jvmSettings(/* ... */)
// configure Scala-Native settings
.nativeSettings(/* ... */) // defined in sbt-scala-native
// Optional in sbt 1.x (mandatory in sbt 0.13.x)
lazy val barJS = bar.js
lazy val barJVM = bar.jvm
lazy val barNative = bar.native
lazy val foo =
crossProject(JSPlatform, JVMPlatform, NativePlatform)
.settings(sharedSettings)
.settings(
// %%% now include Scala Native. It applies to all selected platforms
libraryDependencies += "org.example" %%% "foo" % "1.2.3"
)
// Optional in sbt 1.x (mandatory in sbt 0.13.x)
lazy val fooJS = foo.js
lazy val fooJVM = foo.jvm
lazy val fooNative = foo.nativeIf you mainly use one "default" platform in your everyday development, you can tell sbt-crossproject not to add the platform suffix to its project ID. For example, assuming you mainly compile and test for the JVM, you can write:
lazy val bar =
crossProject(JSPlatform, JVMPlatform, NativePlatform)
.withoutSuffixFor(JVMPlatform)
.crossType(...)
.settings(...)
// Optional in sbt 1.x (mandatory in sbt 0.13.x)
lazy val barJS = bar.js
lazy val barJVM = bar.jvm
lazy val barNative = bar.nativeThe call to withoutSuffixFor must come first after the call to crossProject(), otherwise it will not compile.
Now, in the sbt prompt, you can do
> bar/test
to test the JVM platform (instead of barJVM/test).
This of course applies to all tasks.
Note that inside the build, you still need to use barJVM to the JVM Project.
withoutSuffixFor only changes the id of the project, which is used in the sbt prompt.
Within the settings of a crossProject, you can detect the platform for which those settings are being applied to with crossProjectPlatform.
Here is a contrived example:
lazy val bar =
crossProject(JSPlatform, JVMPlatform, NativePlatform)
.crossType(...)
.settings(
name := "bar for " + crossProjectPlatform.value.identifier
)
...In project/plugins.sbt:
addSbtPlugin("org.portable-scala" % "sbt-scala-native-crossproject" % "1.3.2")
addSbtPlugin("org.scala-native" % "sbt-scala-native" % "0.5.4")In build.sbt:
val sharedSettings = Seq(scalaVersion := "2.11.12")
lazy val bar =
// select supported platforms
crossProject(JVMPlatform, NativePlatform)
.settings(sharedSettings)
// configure JVM settings
.jvmSettings(/* ... */)
// configure Scala-Native settings
.nativeSettings(/* ... */) // defined in sbt-scala-native
// Optional in sbt 1.x (mandatory in sbt 0.13.x)
lazy val barJVM = bar.jvm
lazy val barNative = bar.nativeWe carefully implemented sbt-crossproject to be mostly source compatible with Scala.js crossProject
In project/plugins.sbt:
addSbtPlugin("org.portable-scala" % "sbt-scalajs-crossproject" % "1.3.2")
addSbtPlugin("org.scala-js" % "sbt-scalajs" % "0.6.33")In build.sbt:
// shadow sbt-scalajs' crossProject and CrossType from Scala.js 0.6.x
import sbtcrossproject.CrossPlugin.autoImport.{crossProject, CrossType}
lazy val bar =
// select supported platforms
crossProject(JSPlatform, JVMPlatform)
.crossType(CrossType.Pure) // [Pure, Full, Dummy], default: CrossType.Full
.settings(/* ... */)
.jsSettings(/* ... */) // defined in sbt-scalajs-crossproject
.jvmSettings(/* ... */)
// Optional in sbt 1.x (mandatory in sbt 0.13.x)
lazy val barJS = bar.js
lazy val barJVM = bar.jvmimport org.portablescala.sbtplatformdeps.PlatformDepsPlugin.autoImport._
import sbtcrossproject.CrossPlugin.autoImport.{crossProject, CrossType, _}
import scalajscrossproject.ScalaJSCrossPlugin.autoImport._
import scalanativecrossproject.ScalaNativeCrossPlugin.autoImport._
Setting a specific CrossType allows the definition of a custom source tree layout for managing native-, js- and jvm-specific sources in directories of their own.
sbt-cross provides by default 3 implementations of the CrossType class that one can
pass as .crossType parameter:
.crossType(CrossType.Pure):
.
├── .js
├── .jvm
├── .native
└── src
This layout is preferred for codebases which do not contain any platform-specific code.
Since this is the case of most existing sbt projects it is often desired during conversion to sbt-cross to place the cross-project at the root of the project source tree.
This can be done with the following set of options:
lazy val foo = crossProject.crossType(CrossType.Pure).in(file("."))
.crossType(CrossType.Full)
.
├── js
├── jvm
├── native
└── shared
This layout gives full control by providing a shared directory for common code.
.crossType(CrossType.Dummy)
.
├── js
├── jvm
└── native
.crossType({/*custom*/})
One can easily extend CrossType and provide a custom tree structure.