Кросс-версии SBT Scala, с агрегацией и зависимостями

Я борюсь с тем, как crossScalaVersions работает с подпроектами.

У меня есть проект, который компилируется с 2.10 (foo) и проект, который компилируется с 2.11 (bar). Они разделяют кросс-скомпилированный проект (общий).

Как мне скомпилировать проекты foo и 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")
)

проект / build.properties

sbt.version=0.13.7

Foo / SRC / Основной / Scala / Foo.scala

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

бар / SRC / главная / Скала / 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)

общий / SRC / основной / Scala / Common.scala

class C {}

Попытка 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

Попытка 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

Попытка 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

Попытка 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

Попытка 5

Я даже пытался определить common_2_10 а также common_2_11 проекты с тем же базовым каталогом, но с разными версиями Scala. Я помню, что читал, что цели имеют пространство имен по версии Scala, но SBT говорит, что существует конфликт.

$ 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)

Единственное, что мне удалось - это указать версии вручную:

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

Но это много команд, они никогда не могут использовать параллелизм и исключают полное использование (1) агрегации проектов и (2) перекрестного построения.

Я что-то упускаю из-за намерения crossScalaVersions? Или есть способ заставить его играть хорошо с остальной частью SBT, и для меня, чтобы собрать мои разнородные проекты?

2 ответа

Решение

Я в итоге объявил общее дважды, по одному разу для каждой версии.

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"
)

Обратите внимание, что я должен был сделать целевые каталоги другими, иначе SBT отклонит его, потому что они перекрываются.

Также обратите внимание, что def марки commonProject не включает волшебный (основанный на отражении) поиск SBT для определения проекта.


Это не самый красивый, но надежный, читаемый и разумный. Все команды / задачи работают так, как можно было бы ожидать.

С одной стороны, это даже лучше, чем crossScalaVersionsв этом 2.10 и 2.11 проекты теперь могут быть скомпилированы параллельно, что не происходит с crossScalaVersions:)


РЕДАКТИРОВАТЬ: я создал плагин SBT, sbt-cross, чтобы помочь с этим.

Проверьте мой sbt-doge:

плагин sbt для агрегирования задач по подпроектам и их кросс-фалам

Другие вопросы по тегам