mathieu
mathieu

Reputation: 2428

sbt with sub-modules and multiple scala versions

I'm building a scala applications with these module and dependencies :

I'm trying to have all the 3 modules in a single sbt build :

import sbt._
import Keys._

lazy val root = (project in file("."))
                .aggregate(common, A, B)

lazy val common = (project in file("common"))

lazy val A = (project in file("A"))
             .dependsOn(common)

lazy val B = (project in file("B"))
             .dependsOn(common)

I've read things about crossScalaVersions, but whatever combination I try in root build, or in common, etc, I can't manage to make this work properly.

Any clue ? I'm using sbt 0.13.8 by the way.

Upvotes: 2

Views: 2451

Answers (2)

Atais
Atais

Reputation: 11275

Using bare sbt this might not be possible.

An example build.sbt file representing such situation:

lazy val common = (project in file("common"))
                  .settings(crossScalaVersions := Seq("2.10.6", "2.11.8"))

lazy val A = (project in file("A"))
             .settings(scalaVersion := "2.10.6")
             .dependsOn(common)

lazy val B = (project in file("B"))
             .settings(scalaVersion := "2.11.8")
             .dependsOn(common)

This will work just fine.

Now. A compilation of any project leads to a creation of a package. Even for the root. If you follow the console, at some point it says:

Packaging /project/com.github.atais/target/scala-2.10/root_2.10-0.1.jar

So as you see sbt needs to decide on some Scala version, just to build this jar! That being said your projects A and B must have a common Scala version so they can be aggregated in a common project root.

Therefore, you can't have:

lazy val root = (project in file("."))
                .aggregate(common, A, B)

if they do not share any Scala version they could be built with.

But... sbt-cross to the rescue

You can use sbt-cross plugin to help you out.

In project/plugins.sbt, add

addSbtPlugin("com.lucidchart" % "sbt-cross" % "3.2")

And define your build.sbt in a following way:

lazy val common = (project in file("common")).cross

lazy val common_2_11 = common("2.11.8")
lazy val common_2_10 = common("2.10.6")

lazy val A = (project in file("A"))
             .settings(scalaVersion := "2.10.6")
             .dependsOn(common_2_10)

lazy val B = (project in file("B"))
             .settings(scalaVersion := "2.11.8")
             .dependsOn(common_2_11)

lazy val root = (project in file("."))
                .aggregate(common, A, B)

And then it works :-)!

Upvotes: 2

jlaitio
jlaitio

Reputation: 1948

In my experience sbt multi-module builds are quite finicky to get to work reliably if you require any extra hoops to jump through such as this requirement.

Have you considered the simpler way to achieve this:

  • publish your common dependency (sbt publish-local if you only need to access it yourself)
  • make two projects A and B
  • make both A and B import common as a dependency

Upvotes: 1

Related Questions