parallel cross building, part 3

in

This is part 3 of the post about sbt-projectmatrix, an experimental plugin that I've been working to improve the cross building in sbt. Here's part 1 and part 2. I've just released 0.5.0.

recap: building against multiple Scala versions

After adding sbt-projectmatrix to your build, here's how you can set up a matrix with two Scala versions.

ThisBuild / organization := "com.example"
ThisBuild / scalaVersion := "2.12.10"
ThisBuild / version      := "0.1.0-SNAPSHOT"
 
lazy val core = (projectMatrix in file("core"))
  .settings(
    name := "core"
  )
  .jvmPlatform(scalaVersions = Seq("2.12.10", "2.11.12"))

This will create subprojects coreJVM2_11 and coreJVM2_12. Unlike ++ style stateful cross building, these will build in parallel. This part has not changed.

Previous post also discussed the idea of VirtualAxis so a row can express multiple concepts.

what's new in 0.5.0

0.4.0 came pretty close, but there are some issue I ran into when I tried to use it in a real project. First is the lack of % syntax.

It's fairly common for subprojects to depend only from Test configuration, or depend on Compile from Compile, and Test from Test. 0.5.0 adds % to make this possible.

lazy val app = (projectMatrix in file("app"))
  .dependsOn(core % "compile->compile;test->test")
  .settings(
    name := "app"
  )
  .jvmPlatform(scalaVersions = Seq("2.12.10"))
 
lazy val core = (projectMatrix in file("core"))
  .settings(
    name := "core"
  )
  .jvmPlatform(scalaVersions = Seq("2.12.10", "2.13.1"))

Another feature that's available to Project is .configure(...) method. It takes a vararg of Project => Project functions, and applies them in order. Since some of the builds I deal with uses .configure(...) this helps me migrate from Project to ProjectMatrix.

zincApiInfo example

Here's from Zinc build I'm working:

lazy val compilerInterface = (projectMatrix in internalPath / "compiler-interface")
  .enablePlugins(ContrabandPlugin)
  .settings(
    minimalSettings,
    name := "Compiler Interface",
    exportJars := true,
    crossPaths := false,
  )
  .jvmPlatform(autoScalaLibrary = false)
  .configure(addSbtUtilInterface)
 
lazy val zincApiInfo = (projectMatrix in internalPath / "zinc-apiinfo")
  .dependsOn(compilerInterface, compilerBridge, zincClassfile % "compile;test->test")
  .settings(
    name := "zinc ApiInfo",
    compilerVersionDependentScalacOptions,
    mimaSettings,
  )
  .jvmPlatform(scalaVersions = List(scala212, scala213))
  .configure(addBaseSettingsAndTestDeps)

In the above, both compilerInterface and zincApiInfo are project matrices. compilerInterface is how a Java-only matrix looks like, and zincApiInfo is a Scala project matrix with multiple Scala versions.

Unlike the traditional multi-project setup, this would create a subproject for each Scala version so a fairly complex web of projects can be set up without using ++ commands.

summary

  • sbt-projectmatrix enables parallel building of multiple Scala versions and JVM/JS/Native cross building.
  • sbt-projectmatrix 0.5.0 adds % support for inter-matrix dependencies.