Now we can bump up version in one place, and it will be reflected
across subprojects when you reload the build.

Build-wide settings

Another a bit advanced technique for factoring out common settings
across subprojects is to define the settings scoped to ThisBuild. (See Scopes)

Dependencies

Projects in the build can be completely independent of one another, but
usually they will be related to one another by some kind of dependency.
There are two types of dependencies: aggregate and classpath.

Aggregation

Aggregation means that running a task on the aggregate project will also
run it on the aggregated projects. For example,

aggregate in update is the aggregate key scoped to the update task. (See
scopes.)

Note: aggregation will run the aggregated tasks in parallel and with no
defined ordering between them.

Classpath dependencies

A project may depend on code in another project. This is done by adding
a dependsOn method call. For example, if core needed util on its
classpath, you would define core as:

lazy val core = project.dependsOn(util)

Now code in core can use classes from util. This also creates an
ordering between the projects when compiling them; util must be updated
and compiled before core can be compiled.

To depend on multiple projects, use multiple arguments to dependsOn,
like dependsOn(bar, baz).

Per-configuration classpath dependencies

foo dependsOn(bar) means that the compile configuration in foo depends
on the compile configuration in bar. You could write this explicitly as
dependsOn(bar % "compile->compile").

The -> in "compile->compile" means “depends on” so "test->compile"
means the test configuration in foo would depend on the compile
configuration in bar.

Omitting the ->config part implies ->compile, so
dependsOn(bar % "test") means that the test configuration in foo depends
on the Compile configuration in bar.

A useful declaration is "test->test" which means test depends on test.
This allows you to put utility code for testing in bar/src/test/scala
and then use that code in foo/src/test/scala, for example.

You can have multiple configurations for a dependency, separated by
semicolons. For example,
dependsOn(bar % "test->test;compile->compile").

Default root project

If a project is not defined for the root directory in the build, sbt
creates a default one that aggregates all other projects in the build.

Because project hello-foo is defined with base = file("foo"), it will be
contained in the subdirectory foo. Its sources could be directly under
foo, like foo/Foo.scala, or in foo/src/main/scala. The usual sbt
directory structure applies underneath foo with the
exception of build definition files.

Any .sbt files in foo, say foo/build.sbt, will be merged with the build
definition for the entire build, but scoped to the hello-foo project.

If your whole project is in hello, try defining a different version
(version := "0.6") in hello/build.sbt, hello/foo/build.sbt, and
hello/bar/build.sbt. Now show version at the sbt interactive prompt. You
should get something like this (with whatever versions you defined):

hello-foo/*:version was defined in hello/foo/build.sbt,
hello-bar/*:version was defined in hello/bar/build.sbt, and
hello/*:version was defined in hello/build.sbt. Remember the
syntax for scoped keys. Each version key is scoped to a
project, based on the location of the build.sbt. But all three build.sbt
are part of the same build definition.

Each project’s settings can go in .sbt files in the base directory of
that project, while the .scala file can be as simple as the one shown
above, listing the projects and base directories. There is no need to
put settings in the .scala file.*

You may find it cleaner to put everything including settings in .scala
files in order to keep all build definition under a single project
directory, however. It’s up to you.

You cannot have a project subdirectory or project/*.scala files in the
sub-projects. foo/project/Build.scala would be ignored.

Navigating projects interactively

At the sbt interactive prompt, type projects to list your projects and
project <projectname> to select a current project. When you run a task
like compile, it runs on the current project. So you don’t necessarily
have to compile the root project, you could compile only a subproject.

You can run a task in another project by explicitly specifying the
project ID, such as subProjectID/compile.

Common code

The definitions in .sbt files are not visible in other .sbt files. In
order to share code between .sbt files, define one or more Scala files
in the project/ directory of the build root.