SBT Scala cross versions, with aggregation and dependencies

匿名 (未验证) 提交于 2019-12-03 00:54:02

问题:

I am struggling with how crossScalaVersions works with subprojects.

I have a project that compiles with 2.10 (foo) and a project that compiles with 2.11 (bar). They share a cross compiled project (common).

How can I compile projects foo and bar?


build.sbt

lazy val root = (project in file(".")).aggregate(foo, bar).settings(   crossScalaVersions := Seq("2.10.4", "2.11.4") )  lazy val foo = (project in file("foo")).dependsOn(common).settings(   crossScalaVersions := Seq("2.10.4"),   scalaVersion := "2.10.4" )  lazy val bar = (project in file("bar")).dependsOn(common).settings(   crossScalaVersions := Seq("2.11.4"),   scalaVersion := "2.11.4" )  lazy val common = (project in file("common")).settings(   crossScalaVersions := Seq("2.10.4", "2.11.4") ) 

project/build.properties

sbt.version=0.13.7 

foo/src/main/scala/Foo.scala

object Foo {   <xml>{new C}</xml> } 

bar/src/main/scala/Bar.scala

case class Bar(a: C, b: C, c: C, d: C, e: C, f: C, g: C,   h: C, i: C, j: C, k: C, l: C, m: C, n: C, o: C, p: C,   q: C, r: C, s: C, t: C, u: C, v: C, w: C, x: C, y: C,   z: C) 

common/src/main/scala/Common.scala

class C {} 

Attempt 1

$ sbt compile [info] Resolving jline#jline;2.12 ... [warn]  :::::::::::::::::::::::::::::::::::::::::::::: [warn]  ::          UNRESOLVED DEPENDENCIES         :: [warn]  :::::::::::::::::::::::::::::::::::::::::::::: [warn]  :: common#common_2.11;0.1-SNAPSHOT: not found [warn]  :::::::::::::::::::::::::::::::::::::::::::::: [warn]  [warn]  Note: Unresolved dependencies path: [warn]      common:common_2.11:0.1-SNAPSHOT [warn]        +- bar:bar_2.11:0.1-SNAPSHOT sbt.ResolveException: unresolved dependency: common#common_2.11;0.1-SNAPSHOT: not found 

Attempt 2

$ sbt +compile [error] /home/paul/test/bar/src/main/scala/Bar.scala:1: Implementation restriction: case classes cannot have more than 22 parameters. [error] case class Bar(a: C, b: C, c: C, d: C, e: C, f: C, g: C, [error]            ^ [error] one error found [error] (bar/compile:compile) Compilation failed 

Attempt 3

$ sbt foo/compile bar/compile [warn]  :::::::::::::::::::::::::::::::::::::::::::::: [warn]  ::          UNRESOLVED DEPENDENCIES         :: [warn]  :::::::::::::::::::::::::::::::::::::::::::::: [warn]  :: common#common_2.11;0.1-SNAPSHOT: not found [warn]  :::::::::::::::::::::::::::::::::::::::::::::: [warn]  [warn]  Note: Unresolved dependencies path: [warn]      common:common_2.11:0.1-SNAPSHOT [warn]        +- bar:bar_2.11:0.1-SNAPSHOT sbt.ResolveException: unresolved dependency: common#common_2.11;0.1-SNAPSHOT: not found 

Attempt 4

$ sbt +foo/compile +bar/compile [error] /home/paul/test3/foo/src/main/scala/Foo.scala:2: To compile XML syntax, the scala.xml package must be on the classpath. [error] Please see http://docs.scala-lang.org/overviews/core/scala-2.11.html#scala-xml. [error]   <xml>{new C}</xml> [error]   ^ [error] one error found [error] (foo/compile:compile) Compilation failed 

Attempt 5

I even tried defining common_2_10 and common_2_11 projects with that same base directory but different scala versions. I recall reading that targets are namespaced by Scala version, but SBT says there is a conflict.

$ sbt [error] Overlapping output directories:/home/paul/test3/common/target: [error]     ProjectRef(file:/home/paul/test3/,common_2_10) [error]     ProjectRef(file:/home/paul/test3/,common_2_11) 

The only thing I've gotten to work is manually specifying versions:

$ sbt ++2.10.4 foo/compile ++2.11.4 bar/compile 

But this is a lot of commands, can never use parallelism, and obviates the whole use of (1) project aggregation and (2) cross building.

Am I missing something fundamental about the intent of crossScalaVersions? Or is there a way to have it play well with the rest of SBT, and for me to compile my heterogeneous projects?

回答1:

I wound up declaring common twice, once for each version.

lazy val root = (project in file(".")).aggregate(foo, bar)  lazy val foo = (project in file("foo")).dependsOn(common_2_10).settings(   scalaVersion := "2.10.4" )  lazy val bar = (project in file("bar")).dependsOn(common_2_11).settings(   scalaVersion := "2.11.4" )  def commonProject = (project in file("common")).settings(   target := baseDirectory.value / s"target-${scalaVersion.value}" )  lazy val common_2_10 = commonProject.settings(   scalaVersion := "2.10.4" )  lazy val common_2_11 = commonProject.settings(   scalaVersion := "2.11.4" ) 

Note that I had to make the target directories different, or else SBT would reject it because they overlapped.

Also note that def makes commonProject not included the SBT's magical (reflection-based) search for project definitions.


This isn't the prettiest, but it is robust, readable, and reasonable. All commands/tasks work as one might expect.

In one way this is even better than crossScalaVersions, in that 2.10 and 2.11 projects can now be compiled in parallel, which does not happen with crossScalaVersions :)


EDIT: I created an SBT plugin, sbt-cross, to help out with this.



回答2:

Check out my sbt-doge:

sbt plugin to aggregate tasks across subprojects and their crossScalaVersions



易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!