Scala : multi project sbt setup

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._

  // Sub-project specific dependencies
  val commonDeps = Seq (
     jacksonjson,
     scalatest
  )

  val serverDeps = Seq (
     scalatest
  )


  lazy val demoApp = Project (
    "SachasSBTDemo-App",
    file ("SachasSBTDemo-App"),
    settings = buildSettings
  )
  //build these projects when main App project gets built
  .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
  )
  //build these projects when main App project gets built
  .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
  )
  //build these projects when main App project gets built
  .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"
}

  // Sub-project specific dependencies
  val serverDeps = Seq (
     scalatest
  )

  .....
  .....
  lazy val server = Project (
    "server",
    file ("SachasSBTDemo-Server"),
    //bring in the library dependencies
    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:

image

 

Or like on the file system

image

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

Advertisements

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s

%d bloggers like this: