Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

In SBT 0.13, does scalaVersion still control the version of scala used for compile, run and test?

Tags:

scala

sbt

When upgrading our build from 12.4 to 13.1 I observed that although the build specified scalaVersion := "2.10.2", the resulting archive (created via the sbt-pack plugin) contained scala-library-2.10.3.jar. A quick check confirmed that the 12.4 build was including scala-library-2.10.2.jar.

It appears that sbt 0.13 included a change to treat the scala libraries as normal dependencies, with the consequence that if a project dependency was built with a later 2.10.x version of scala then that transitive dependency will "win" the ivy dependency resolution conflict resolution, and the compile, test and run classpaths will contain the later version of scala libraries.

Is this the desired behavior, or a bug in sbt 0.13?

If the desired behavior, then does that mean I have to use the mechanisms to "force/override" the conflict resolution to use my desired version of the scala libraries? (If so, the scalaVersion configuration setting seems a bit pointless....)

Here is an extremely minimal test case to illustrate the behavior:

test-proj/
  build.sbt
  project/
    build.properties

build.sbt:

scalaVersion := "2.10.2"
//scalaVersion := "2.10.3"

libraryDependencies += "com.typesafe.akka" %% "akka-actor" % "2.3.0"
//libraryDependencies += "com.typesafe.akka" %% "akka-actor" % "2.2.4"

build.properties:

sbt.version=0.13.1

Akka 2.2.4 was built against scala 2.10.2, so firing up sbt and running "update", "show update", "show compile:dependencyClasspath", "show test:dependencyClasspath" and "show runtime:dependencyClasspath" all show scala-library 2.10.2 on the classpath.

Switching to Akka 2.3.0, which was built against scala 2.10.3, results in scala-library 2.10.3 appearing on all the classpaths, and "show update" clearly shows 2.10.2 being evicted by Ivy's conflict resolution.

Interestingly (and inconsistently), entering the REPL in both cases (via the sbt console command) results in scala 2.10.2 being utilized.

According to the docs, in sbt 0.13

The scalaVersion configures the version of Scala used for compilation. By default, sbt also adds a dependency on the Scala library with this version.

Based on that, I would expect the compilation classpath above to include 2.10.2 in both circumstances.

However, the release notes for 0.13 say

Scala dependencies (like scala-library and scala-compiler) are now resolved via the normal update task

which does at least explain the observed behavior.

like image 320
jtp Avatar asked Mar 21 '14 06:03

jtp


1 Answers

sbt 0.13.0 Changes

You wrote:

It appears that sbt 0.13 included a change to treat the scala libraries as normal dependencies, with the consequence that if a project dependency was built with a later 2.10.x version of scala then that transitive dependency will "win" the ivy dependency resolution conflict resolution, and the compile, test and run classpaths will contain the later version of scala libraries.

sbt 0.13.0 Changes has somewhat conflicting note on this issue. Features, fixes, changes with compatibility implications section says:

  • sbt no longer overrides the Scala version in dependencies. This allows independent configurations to depend on different Scala versions and treats Scala dependencies other than scala-library as normal dependencies. However, it can result in resolved versions other than scalaVersion for those other Scala libraries.

Resolving Scala dependencies section says:

Scala dependencies (like scala-library and scala-compiler) are now resolved via the normal update task.

(Emphasis added by Eugene) So the quick answer to your "Is this the desired behavior, or a bug in sbt 0.13?" as you've already answered yourself is: In sbt 0.13.x, this behavior seems to be intended. Akka 2.3.0 depends on scala-library 2.10.3, and Ivy has evicted scala-library 2.10.2 in favor of 2.10.3.

dependencyOverrides

To workaround this, you can use dependencyOverrides setting as follows:

dependencyOverrides += "org.scala-lang" % "scala-library" % scalaVersion.value

Before:

sbt-so-22551430> show fullClasspath
[info] List(... Attributed(/Users/xxx/.sbt/0.13/boot/scala-2.10.3/lib/scala-library.jar) ...)

After:

sbt-so-22551430> show fullClasspath
[info] List(... Attributed(/Users/xxx/.ivy2/cache/org.scala-lang/scala-library/jars/scala-library-2.10.2.jar) ...)

Is this behavior desirable?

Your question was not whether if this is by design, but if this is desirable. I think the current behavior is quite surprising, and sbt should at least improve on notifying the build users of this behavior. And perhaps change its default Ivy conflict management policy to force() the version specified in scalaVersion. Here are two GitHub issues I created:

  • shell should display all evicted libraries on start up #1200
  • provide some means of forcing scala-library version to scalaVersion #1201
like image 94
Eugene Yokota Avatar answered Nov 15 '22 21:11

Eugene Yokota