2012-09-15 00:08:35 +02:00
|
|
|
====================
|
|
|
|
|
Multi-Project Builds
|
|
|
|
|
====================
|
|
|
|
|
|
|
|
|
|
This page introduces multiple projects in a single build.
|
|
|
|
|
|
|
|
|
|
Please read the earlier pages in the Getting Started Guide first, in
|
|
|
|
|
particular you need to understand :doc:`build.sbt <Basic-Def>` and
|
|
|
|
|
:doc:`.scala build definition <Full-Def>` before reading this page.
|
|
|
|
|
|
|
|
|
|
Multiple projects
|
|
|
|
|
-----------------
|
|
|
|
|
|
|
|
|
|
It can be useful to keep multiple related projects in a single build,
|
|
|
|
|
especially if they depend on one another and you tend to modify them
|
|
|
|
|
together.
|
|
|
|
|
|
2013-07-29 13:27:17 +02:00
|
|
|
Each sub-project in a build has its own `src/main/scala`, generates
|
|
|
|
|
its own jar file when you run `package`, and in general works like any
|
2012-09-15 00:08:35 +02:00
|
|
|
other project.
|
|
|
|
|
|
2013-07-29 13:27:17 +02:00
|
|
|
Defining projects in a `.scala` file
|
2012-09-15 00:08:35 +02:00
|
|
|
--------------------------------------
|
|
|
|
|
|
|
|
|
|
To have multiple projects, you must declare each project and how they
|
2013-07-29 13:27:17 +02:00
|
|
|
relate in a `.scala` file; there's no way to do it in a `.sbt` file.
|
|
|
|
|
However, you can define settings for each project in `.sbt` files.
|
|
|
|
|
Here's an example of a `.scala` file which defines a root project
|
|
|
|
|
`hello`, where the root project aggregates two sub-projects,
|
|
|
|
|
`hello-foo` and `hello-bar`:
|
2012-09-15 00:08:35 +02:00
|
|
|
|
|
|
|
|
::
|
|
|
|
|
|
|
|
|
|
import sbt._
|
|
|
|
|
import Keys._
|
|
|
|
|
|
|
|
|
|
object HelloBuild extends Build {
|
|
|
|
|
lazy val root = Project(id = "hello",
|
|
|
|
|
base = file(".")) aggregate(foo, bar)
|
|
|
|
|
|
|
|
|
|
lazy val foo = Project(id = "hello-foo",
|
|
|
|
|
base = file("foo"))
|
|
|
|
|
|
|
|
|
|
lazy val bar = Project(id = "hello-bar",
|
|
|
|
|
base = file("bar"))
|
|
|
|
|
}
|
|
|
|
|
|
2013-07-29 13:27:17 +02:00
|
|
|
sbt finds the list of `Project` objects using reflection, looking for
|
|
|
|
|
fields with type `Project` in the `Build` object.
|
2012-09-15 00:08:35 +02:00
|
|
|
|
2013-07-29 13:27:17 +02:00
|
|
|
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 :doc:`directory structure <Directories>`
|
|
|
|
|
applies underneath `foo` with the exception of build definition files.
|
2012-09-15 00:08:35 +02:00
|
|
|
|
2013-07-29 13:27:17 +02:00
|
|
|
Any `.sbt` files in `foo`, say `foo/build.sbt`, will be merged
|
2012-09-15 00:08:35 +02:00
|
|
|
with the build definition for the entire build, but scoped to the
|
2013-07-29 13:27:17 +02:00
|
|
|
`hello-foo` project.
|
2012-09-15 00:08:35 +02:00
|
|
|
|
2013-07-29 13:27:17 +02:00
|
|
|
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
|
2012-09-15 00:08:35 +02:00
|
|
|
prompt. You should get something like this (with whatever versions you
|
|
|
|
|
defined):
|
|
|
|
|
|
2012-09-19 02:12:32 +02:00
|
|
|
.. code-block:: console
|
2012-09-15 00:08:35 +02:00
|
|
|
|
|
|
|
|
> show version
|
|
|
|
|
[info] hello-foo/*:version
|
|
|
|
|
[info] 0.7
|
|
|
|
|
[info] hello-bar/*:version
|
|
|
|
|
[info] 0.9
|
|
|
|
|
[info] hello/*:version
|
|
|
|
|
[info] 0.5
|
|
|
|
|
|
2013-07-29 13:27:17 +02:00
|
|
|
`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
|
|
|
|
|
:doc:`syntax for scoped keys <Scopes>`. 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.
|
2012-09-15 00:08:35 +02:00
|
|
|
|
2013-07-29 13:27:17 +02:00
|
|
|
*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
|
2012-09-15 00:08:35 +02:00
|
|
|
shown above, listing the projects and base directories. *There is no
|
2013-07-29 13:27:17 +02:00
|
|
|
need to put settings in the `.scala` file.*
|
2012-09-15 00:08:35 +02:00
|
|
|
|
|
|
|
|
You may find it cleaner to put everything including settings in
|
2013-07-29 13:27:17 +02:00
|
|
|
`.scala` files in order to keep all build definition under a single
|
|
|
|
|
`project` directory, however. It's up to you.
|
2012-09-15 00:08:35 +02:00
|
|
|
|
2013-07-29 13:27:17 +02:00
|
|
|
You cannot have a `project` subdirectory or `project/*.scala` files
|
|
|
|
|
in the sub-projects. `foo/project/Build.scala` would be ignored.
|
2012-09-15 00:08:35 +02:00
|
|
|
|
|
|
|
|
Aggregation
|
|
|
|
|
-----------
|
|
|
|
|
|
|
|
|
|
Projects in the build can be completely independent of one another, if
|
|
|
|
|
you want.
|
|
|
|
|
|
|
|
|
|
In the above example, however, you can see the method call
|
2013-07-29 13:27:17 +02:00
|
|
|
`aggregate(foo, bar)`. This aggregates `hello-foo` and `hello-bar`
|
2012-09-15 00:08:35 +02:00
|
|
|
underneath the root project.
|
|
|
|
|
|
|
|
|
|
Aggregation means that running a task on the aggregate project will also
|
|
|
|
|
run it on the aggregated projects. Start up sbt with two subprojects as
|
2013-07-29 13:27:17 +02:00
|
|
|
in the example, and try `compile`. You should see that all three
|
2012-09-15 00:08:35 +02:00
|
|
|
projects are compiled.
|
|
|
|
|
|
2013-07-29 13:27:17 +02:00
|
|
|
*In the project doing the aggregating*, the root `hello` project in
|
2012-09-15 00:08:35 +02:00
|
|
|
this case, you can control aggregation per-task. So for example in
|
2013-07-29 13:27:17 +02:00
|
|
|
`hello/build.sbt` you could avoid aggregating the `update` task:
|
2012-09-15 00:08:35 +02:00
|
|
|
|
|
|
|
|
::
|
|
|
|
|
|
|
|
|
|
aggregate in update := false
|
|
|
|
|
|
2013-07-29 13:27:17 +02:00
|
|
|
`aggregate in update` is the `aggregate` key scoped to the
|
|
|
|
|
`update` task, see :doc:`scopes <Scopes>`.
|
2012-09-15 00:08:35 +02:00
|
|
|
|
|
|
|
|
Note: aggregation will run the aggregated tasks in parallel and with no
|
|
|
|
|
defined ordering.
|
|
|
|
|
|
|
|
|
|
Classpath dependencies
|
|
|
|
|
----------------------
|
|
|
|
|
|
|
|
|
|
A project may depend on code in another project. This is done by adding
|
2013-07-29 13:27:17 +02:00
|
|
|
a `dependsOn` method call. For example, if `hello-foo` needed
|
|
|
|
|
`hello-bar` on its classpath, you would write in your `Build.scala`:
|
2012-09-15 00:08:35 +02:00
|
|
|
|
|
|
|
|
::
|
|
|
|
|
|
|
|
|
|
lazy val foo = Project(id = "hello-foo",
|
|
|
|
|
base = file("foo")) dependsOn(bar)
|
|
|
|
|
|
2013-07-29 13:27:17 +02:00
|
|
|
Now code in `hello-foo` can use classes from `hello-bar`. This also
|
2012-09-15 00:08:35 +02:00
|
|
|
creates an ordering between the projects when compiling them;
|
2013-07-29 13:27:17 +02:00
|
|
|
`hello-bar` must be updated and compiled before `hello-foo` can be
|
2012-09-15 00:08:35 +02:00
|
|
|
compiled.
|
|
|
|
|
|
2013-07-29 13:27:17 +02:00
|
|
|
To depend on multiple projects, use multiple arguments to `dependsOn`,
|
|
|
|
|
like `dependsOn(bar, baz)`.
|
2012-09-15 00:08:35 +02:00
|
|
|
|
|
|
|
|
Per-configuration classpath dependencies
|
|
|
|
|
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
|
|
|
|
|
2013-07-29 13:27:17 +02:00
|
|
|
`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")`.
|
2012-09-15 00:08:35 +02:00
|
|
|
|
2013-07-29 13:27:17 +02:00
|
|
|
The `->` in `"compile->compile"` means "depends on" so
|
|
|
|
|
`"test->compile"` means the `Test` configuration in `foo` would
|
|
|
|
|
depend on the `Compile` configuration in `bar`.
|
2012-09-15 00:08:35 +02:00
|
|
|
|
2013-07-29 13:27:17 +02:00
|
|
|
Omitting the `->config` part implies `->compile`, so
|
|
|
|
|
`dependsOn(bar % "test")` means that the `Test` configuration in
|
|
|
|
|
`foo` depends on the `Compile` configuration in `bar`.
|
2012-09-15 00:08:35 +02:00
|
|
|
|
2013-07-29 13:27:17 +02:00
|
|
|
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`,
|
2012-09-15 00:08:35 +02:00
|
|
|
for example.
|
|
|
|
|
|
|
|
|
|
You can have multiple configurations for a dependency, separated by
|
|
|
|
|
semicolons. For example,
|
2013-07-29 13:27:17 +02:00
|
|
|
`dependsOn(bar % "test->test;compile->compile")`.
|
2012-09-15 00:08:35 +02:00
|
|
|
|
|
|
|
|
Navigating projects interactively
|
|
|
|
|
---------------------------------
|
|
|
|
|
|
2013-07-29 13:27:17 +02:00
|
|
|
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
|
2012-09-15 00:08:35 +02:00
|
|
|
necessarily have to compile the root project, you could compile only a
|
|
|
|
|
subproject.
|
|
|
|
|
|
|
|
|
|
Next
|
|
|
|
|
----
|
|
|
|
|
|
|
|
|
|
Move on to create :doc:`custom settings <Custom-Settings>`.
|