Scope basics
This page describes scopes.
The whole story about keys
Previously we pretended that a key like name corresponded
to one entry in sbt's map of key-value pairs. This was a simplification.
In the real builds, each key can have an associated value in more than one
context, called a scope.
Some concrete examples:
- if you have multiple subprojects in your build definition, a key can have a different value in each project.
- the
compilekey may have a different value for your main sources and your test sources, if you want to compile them differently. - the
scalacOptionskey (which contains Scala compiler options) may have different values when compiling class files (compile) or running the REPL (console).
Unified slash syntax
A full scope in sbt is described using the unified slash syntax:
projA / Compile / console / scalacOptions
These represent the three level of scoping:
- The subproject scoping
- The dependency configuration scoping
- The task scoping
Introduced in sbt 1.1, the unified slash syntax can be used in both
the sbt shell and in build.sbt.
Scoping by the subproject
If you put multiple subprojects in a single build, each subproject needs its own settings. From the sbt shell, you can compile a specific subproject as follows:
sbt> projA/compile
Scoping by the dependency configuration
A dependency configuration (or configuration for short) defines a graph of library dependencies, potentially with its own classpath, sources, generated packages, etc.
Some configurations you'll see in sbt:
Compilewhich defines the main code (src/main/scala).Testwhich defines how to compile tests (src/test/scala).Runtimewhich defines the classpath for theruntask.
From the sbt shell, you can compile the test code as follows, which would also compile the main code:
sbt> Test/compile
In build.sbt, you can specify the tests to be forked as follows:
Test / fork := true
Scoping by task
Settings can affect how a task works. For example, the compile task
is affected by the scalacOptions setting.
To support this, a task key (such as compile) can be a scope for
another key (such as scalacOptions).
Various tasks that invoke the Scala compiler (compile, console,
doc) can share keys related to compilation such as scalacOptions. Those keys can have distinct values.
scalaVersion := "3.9.0"
Compile / scalacOptions ++= List("-deprecation", "-Werror", "-Wunused:imports")
Compile / console / scalacOptions --= List("-Werror", "-Wunused:imports")
Inspecting scopes
In sbt shell, you can use the inspect command to understand
keys and their scopes. Try inspect Test / fullClasspath:
sbt:Hello> inspect Test / fullClasspath
[info] Task: Seq[class sbt.internal.util.Attributed]
[info] Description:
[info] The exported classpath, consisting of build products and unmanaged and
managed, internal and external dependencies.
[info] Provided by:
[info] Test / fullClasspath
[info] Defined at:
[info] Defaults.scala:2823
[info] Dependencies:
[info] Test / fullClasspath / streams
[info] Test / exportedProducts
[info] Test / dependencyClasspath
[info] Reverse dependencies:
[info] Test / fgRun
[info] Test / run / bspBuildTargetJvmEnvironmentItem
[info] Test / console
[info] Test / fgRunMain
[info] Test / testLoader
[info] Test / bspBuildTargetJvmEnvironmentItem
....
For more details, see sbt inspect reference guide.