A while ago I wrote a post about how to use SBT (Scala Build Tool):
https://sachabarbs.wordpress.com/2015/10/13/sbt-wheres-my-nuget/
In that post I showed simple usages of SBT. Thing is that was not really that realistic, so I wanted to have a go at a more real world example of this. One where we might have multiple projects, say like this:
SachasSBTDemo-App which depends on 2 sub projects
- SachasSBTDemo-Server
- SachasSBTDemo-Common
So how do we go about doing this with SBT?
There are 5 main steps to do this. Which we look at in turn.
SBT Directory Structure
The first that we need to do is create a new project folder (if you are from Visual Studio / .NET background think of this as the solution folder) called “project”
In here we will create 2 files
build.properties which just lists the version of SBT we will use. It looks like this
sbt.version=0.13.8
SachaSBTDemo.scala is what I have called the other file, but you can call it what you like. Here is the contents of that file, this is the main SBT file that governs how it all hangs together. I will be explaining each of these parts as we go.
import sbt._
import Keys._
object BuildSettings {
val buildOrganization = "sas"
val buildVersion = "1.0"
val buildScalaVersion = "2.11.5"
val buildSettings = Defaults.defaultSettings ++ Seq (
organization := buildOrganization,
version := buildVersion,
scalaVersion := buildScalaVersion
)
}
object Dependencies {
val jacksonjson = "org.codehaus.jackson" % "jackson-core-lgpl" % "1.7.2"
val scalatest = "org.scalatest" % "scalatest_2.9.0" % "1.4.1" % "test"
}
object SachasSBTDemo extends Build {
import Dependencies._
import BuildSettings._
val commonDeps = Seq (
jacksonjson,
scalatest
)
val serverDeps = Seq (
scalatest
)
lazy val demoApp = Project (
"SachasSBTDemo-App",
file ("SachasSBTDemo-App"),
settings = buildSettings
)
.aggregate(common, server)
.dependsOn(common, server)
lazy val common = Project (
"common",
file ("SachasSBTDemo-Common"),
settings = buildSettings ++ Seq (libraryDependencies ++= commonDeps)
)
lazy val server = Project (
"server",
file ("SachasSBTDemo-Server"),
settings = buildSettings ++ Seq (libraryDependencies ++= serverDeps)
) dependsOn (common)
}
Projects
In order to have separate project we need to use the Project item from the SBT library JARs. A minimal Project setup will tell SBT where to create the new Project. Here is an example of a Project, where the folder we expect SBT to create will be called “SachasSBTDemo-App”.
lazy val demoApp = Project (
"SachasSBTDemo-App",
file ("SachasSBTDemo-App"),
settings = buildSettings
)
Project Dependencies
We can also specify Project dependencies using “dependsOn” which takes a Seq of other projects that this Project depends on.
That means that when we apply an action to the Project that is depended on, the Project that has the dependency will also have the action applied.
lazy val demoApp = Project (
"SachasSBTDemo-App",
file ("SachasSBTDemo-App"),
settings = buildSettings
)
.aggregate(common, server)
.dependsOn(common, server)
Project Aggregation
We can also specify Project aggregates results from other projects, using “aggregate” which takes a Seq of other projects that this Project aggregates.
What “aggregate” means is that whenever we apply an action on the aggregating Project we should also see the same action applied to the aggregated Projects.
lazy val demoApp = Project (
"SachasSBTDemo-App",
file ("SachasSBTDemo-App"),
settings = buildSettings
)
.aggregate(common, server)
.dependsOn(common, server)
Library Dependencies
Just like the simple post I did before, we still need to bring in our JAR files using SBT. But this time we come up with a nicer way to manage them. We simply wrap them all up in a simple object, and then use the object to satisfy the various dependencies of the Projects. Much neater.
import sbt._
import Keys._
object Dependencies {
val jacksonjson = "org.codehaus.jackson" % "jackson-core-lgpl" % "1.7.2"
val scalatest = "org.scalatest" % "scalatest_2.9.0" % "1.4.1" % "test"
}
val serverDeps = Seq (
scalatest
)
.....
.....
lazy val server = Project (
"server",
file ("SachasSBTDemo-Server"),
settings = buildSettings ++ Seq (libraryDependencies ++= serverDeps)
) dependsOn (common)
The Finished Product
The final product once run through SBT should be something like this if viewed in IntelliJ IDEA:

Or like on the file system

If you want to grab my source files, they are available here at GitHub : https://github.com/sachabarber/SBT_MultiProject_Demo