SBT
sbt (opens in a new tab) Is one of the most prevalent build tools in the Scala ecosystem.
Here is the official sbt by example (opens in a new tab) page, which is a great outline to get you started, and using sbt.
Despite the complex build/task scenarios it can perform, it is simple to use and get started with. As with most build tools, there are a few idiosyncrasies to familiarize yourself with. This page serves as a quick extension to the official link above, and outlines a couple of the "tricky pieces".
Building Towards: build.sbt
TODO put a final build.sbt
here, so show a "final minimal" file that we're
building up towards, so it doesn't feeling daunting to learn it line-by-line
over the various sections.
ThisBuild / scalaVersion := "3.2.2"
lazy val root = project.in(file("."))
.settings()
The root project
sbt handles building both single and multiple projects. One quirky thing you
should know about right away is the root
project. sbt will automatically
assume there is a root project if you don't define one, which allows you to get
started quickly without a lot of boilerplate definition.
For example, these two build.sbt
files should be functionally equivalent
ThisBuild / scalaVersion := "3.2.2"
lazy val root = project.in(file("."))
.settings(
scalaVersion := "3.2.2"
)
The tricky part comes in when you start adding more projects, or organizing your
code in a sub directory that is not in the <root>
of your path. In that case,
sbt will create a root project, and aggregate all other projects in the build.
For example, if we moved out code from ./
to ./my-project
, our buildt.sbt
file might look like
lazy val myProject = project.in(file("my-project"))
.settings(
scalaVersion := "3.2.2"
)
And if we called sbt compile
, what it's really doing is calling
sbt root/compile
, and aggregating that task to myProject
as well! Explicitly
stated, this might look like:
lazy val root = project.in(file("."))
.aggregate(myProject)
lazy val myProject = project.in(file("my-project"))
.settings(
scalaVersion := "3.2.2"
)
This can be a source of frustration, especially when going from a single project to multiple projects as the source code grows - it might seem like something "just stopped working", because a setting was being applied to the "root" project, what what the "root" project was subtly changed! If this happens, you can just manually add in the root project again (like in the explicit example above), and adjust the settings to what you are expecting in relation to your sub projects - for example maybe you only want the root project to aggregate a subset of you other projects, and not all of them by default.
To help avoid confusion, although you can quickly get started with a one-liner
build.sbt
file like ThisBuild / scalaVersion := "3.2.2"
, you are encouraged
to actually define your projects (even a root one), so that it's more apparent
as to what is going on.
See more info here (opens in a new tab)
ThisBuild
ThisBuild / scalaVersion := "3.2.2"
ThisBuild
is used to factor out common settings across multiple sub-projects.
When a particular (sub-)project doesn't have a specific setting applied, then it
will fall back to a value specified in ThisBuild
See here (opens in a new tab) for more.
Integration Tests
TODO Show how to set up integration tests