I am cross building a scala project with sbt 12.1.
crossScalaVersions := Seq("2.9.2", "2.10.0")
However, it can't find the dependencies because they are named _2.10 not _2.10.0. It seems like it's regular to name your library 2.10 instead of 2.10.0 with the exception of scala-language and scala-compiler. For example, scalaz is not found at http://repo1.maven.org/maven2/org/scalaz/scalaz-core_2.10.0/6.0.4/scalaz-core_2.10.0-6.0.4.pom but at http://repo1.maven.org/maven2/org/scalaz/scalaz-core_2.10/6.0.4/scalaz-core_2.10-6.0.4.pom.
Is there an easy way to handle this without writing custom rules for all of my dependencies?
The actual build.sbt is available online.
Since 2.10.x releases are binary compatible between each other, libraries need to be built only with one version of scala library - and they can (and must) drop the .0 part (if you publish with sbt, it is done automatically). When the maintainer of a library releases a library with _2.10.0 tag, it's a mistake and you should consider filing a bug.
By the way, I looked on your build.sbt - running +compile on it works for me (sbt 0.12.1). Do you experience some errors?
To get the Scala version incorporated into the artifact name in the Scala way, you specify the dependency with the %% operator:
libraryDependencies += "io.backchat.jerkson" %% "jerkson" % "0.7.0"
When the exact match is not available, you can specify the Scala version explicitly (but remember compatibility only exists across patch releases of a given major/minor release of Scala):
libraryDependencies += "io.backchat.jerkson" % "jerkson_2.9.2" % "0.7.0"
Related
I have this line of code in my build.sbt file:
libraryDependencies ++= Seq("com.foo" %% "lib" % "1.2.3")
Imagine that this library depends on "com.bar.lib" lib. Now in my code I can import com.bar.lib._ and it'll work. But I don't want this to compile, so maybe there is SBT plugin out there just for this purpose?
One of libraries I'm using depends on old cats version. I spent really long time to understand why mapN method not works... I just never imported a newer version of cats in the subproject.
SBT offers the intransitive and exclude features to deal with issues like this, as #earldouglas points out. See: https://www.scala-sbt.org/1.x/docs/Library-Management.html
You replied:
I tried to do so, but intransitive() don't import transitive dependencies (so I need to import all of them by hand to make it compile).
Yes, that is what it is for
What I want is something that will warn me about using libraries not directly imported in SBT file.
So you want transitive dependencies on your classpath, but you want the compiler to reject uses of transitive classes in your project code while allowing them in library code?
That is not a sensible approach: at runtime, these transitive dependencies will be on the classpath. The JVM classpath does not distinguish between different kinds of dependencies; such distinction only exists in SBT at build time.
You would be much better served by either
including a newer version of the cats library, overriding the transitive dep or
excluding the transitively included cats library, if it is broken.
However, I think you probably could achieve what you want by setting different dependencies at different build stages:
at Compile stage, include the dependency with intransitive. Your code should compile against your direct dependencies, but fail if you referenced any transitive dependencies
at Runtime stage, include the dependency with its transitive deps
the SBT code might look like this (untested):
(libraryDependencies in Compile) ++= Seq("com.foo" %% "lib" % "1.2.3" intransitive())
(libraryDependencies in Runtime) ++= Seq("com.foo" %% "lib" % "1.2.3")
I have created a libs folder and placed scalascriptengine-1.3.9-2.11.0.jar in there. After that, I right-clicked on the .jar and selected Add Library.
Then, I created Test.scala:
import java.io.File
import com.googlecode.scalascriptengine.ScalaScriptEngine
object Test {
def main(args: Array[String]): Unit = {
val sourceDir = new File("examples/folder")
val sse = ScalaScriptEngine.onChangeRefresh(sourceDir)
}
}
It correctly recognized ScalaScriptEngine, or at least it did not give any warnings or errors. But it did not compile.
According to the library page I edited my build.sbt:
name := "ScalaScriptEngineTest"
version := "1.0"
libraryDependencies += "com.googlecode.scalascriptengine" %% "scalascriptengine" % "1.3.10"
libraryDependencies += "org.scala-lang" % "scala-compiler" % "2.11.1"
But upon refreshing, I get this: http://pastebin.com/GdirttUJ
What am I missing? I am learning scala and it is the first time I am trying to add a library to IntelliJ Idea...
Short answer:
Change the two dependency entries in your build.sbt as follows:
libraryDependencies +=
"com.googlecode.scalascriptengine" % "scalascriptengine" % "1.3.9-2.10.3"
libraryDependencies += "org.scala-lang" % "scala-compiler" % "2.10.4"
Notice I didn't just change the versions -- I replaced your %% with a single %.
This results in you using a slightly older version of ScalaScriptEngine, and I don't know if that will cause any problems for you.
If you're using sbt build dependencies you don't need to be manually placing jars anywhere.
Explanation:
From your log I see that sbt is looking for the ScalaScriptEngine for Scala 2.10. In fact, it's pretty clear that you're running Scala 2.10.4, even though your sbt file expresses a dependency on the 2.11 compiler, which in fact is consistent with the instructions for using ScalaScriptEngine.
On line 23 of the log you can see exactly where it's looking. If you point your browser part way down that path you'll see that there is a version for Scala 2.11 and another directory, scalascriptengine, without a version qualifier. If you dive down the latter, you'll see it's where they keep all the old versions. There isn't a ScalaScriptEngine 1.3.10 (the one you asked for) compiled for Scala 2.10, so your options seem to be to upgrade to Scala 2.11 (which I don't think currently works if you want to use IntelliJ Idea's tight integration with sbt), or you can use ScalaScriptEngine 1.3.9.
You have basically the same problem with your Scala compiler dependency -- it needs the be the Scala version you're using.
I've confirmed the above solution with Scala 2.10.4. I'm playing it a little fast and loose because there isn't a pre compiled version for 2.10.4, and I gambled that the 2.10.3 build will probably work.
Alternatives:
There may be a cleaner way to solve this, but the way the repository is organized makes me doubt it.
You could build the version of your choice with the compiler of your choice, or persuade the ScalaScriptEngine community to do it for you and put it in The Central Repository, but my guess is that 1.3.10 won't build with anything lower than Scala 2.11.
Finally, if you do want to download jars by hand, you may want to read the "Unmanaged dependencies" section of the sbt documentation. Actually, if you're going to use sbt, just read the whole thing a few times.
I come from a background in Ruby, and I use RVM to manage multiple Ruby and gemsets. I have googled around, and I found these two SVM and PVM, not sure what should I use?
Anyone can recommend what should I use to manage multiple scala?
PVM Play Version Manager https://github.com/kaiinkinen/pvm
SVM Scala Version Manager https://github.com/yuroyoro/svm
You don't need a version manager. You need a build tool.
Scala projects work differently than Ruby projects. If you use SBT as a build tool, you specify the Scala version in your build file:
//build.sbt
scalaVersion := "2.11.0" // or some other version
SBT then proceeds to download the specified Scala version for you if it hasn't been downloaded before, and builds and runs your project with this version. If you want, you can even specify which version of SBT you want, and it'll arrange everything for you as well.
This is because Scala, contrary to Ruby, is a compiled language - it must be compiled/built before running. Ruby projects don't have a build process, and can be (attempted to) run on any Ruby version. Scala projects might not build on incompatible versions, let alone run, so you need to specify which Scala version your project is supposed to be built against.
There's also no such thing as gemsets for Scala. For Ruby, gems were originally system-wide libraries and executables, shared by all Ruby scripts on the system. Therefore, gems override each other and you need to maintain gemsets with the specific versions you require for each project. In Scala, a dependency is just a library specifically for your project. They don't override each other, and you just specify which version you need in your build file. SBT then automatically downloads it for you when you build.
This just works:
// myproject1/build.sbt
scalaVersion := "2.10.2"
libraryDependencies += "com.typesafe.akka" %% "akka-actor" % "2.2.0"
// myproject2/build.sbt
scalaVersion := "2.11.0"
libraryDependencies += "com.typesafe.akka" %% "akka-actor" % "2.3.3"
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.
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
I want to add a Java library (e.g. Apache PDFBox) to an sbt project.
This is the Ivy dependency:
dependency org="org.apache.pdfbox" name="pdfbox" rev="1.8.2"
I first tried to do the following:
resolvers += "Sonatype releases" at "http://oss.sonatype.org/content/repositories/releases/"
libraryDependencies += "org.apache.pdfbox" %% "pdfbox" % "1.8.2"
But it gives me errors of the type
[warn] ==== public: tried [warn]
http://repo1.maven.org/maven2/org/apache/pdfbox/pdfbox_2.10/1.8.2/pdfbox_2.10-1.8.2.pom
So I understand that with this syntax I can just manage Scala dependencies. I am sure that there is a way to manage Java dependencies, but how?
I tried to search in Google for "sbt add java dependencies" but did not find (recognize) a relevant result.
You should replace the %% (double percent) with single one.
libraryDependencies += "org.apache.pdfbox" % "pdfbox" % "1.8.2"
The double-percent is a convenience operator, and causes adding the _+scalaVersion postfix inside the path, which is _2.10 in your case. Single percent should fix the problem.
Short answer:
Use
libraryDependencies += "org.apache.pdfbox" % "pdfbox" % "1.8.2"
For java libraries, and
libraryDependencies += "org.scalactic" %% "scalactic" % "3.0.8"
For Scala libraries, where the difference is the double % for the scala library.
Long answer:
Scala is not backward compatible across major version, so a library compiled for scala 2.12.x cannot be used by a project written in scala 2.13.x.
So when writing a scala library, you will need to compile and publish it one time per scala major version you would like to support. When using a library in a project, you would then have to pick the version compiled for the same Scala major version as your are using. Doing this manually would be cumbersome, so SBT has built in support for it.
When publishing a library, you can add the crossScalaVersions key to SBT like
crossScalaVersions := Seq( "2.10.6", "2.11.11", "2.12.3" )
And then publish with sbt +publish. This will make SBT build and publish a version of the library for both scala 2.10.6, 2.11.11 and 2.12.3. Note that the minor number is in-relevant, when it comes to compatibility for libraries. The published libraries, will have the name suffixed with _2.10, _2.11 and _2.12 to show what scala version it is for. An alternative to using the SBT build in support for this, is to use the experimental plugin sbt-projectmatrix as this gives a lot more options, and often faster builds.
When using a library sbt can also help your use the one compiled for the correct scala version, and thats where %% comes into play. When specifying a library without the _ suffix in the name, but instead use %%, then sbt will fill in suffix matching the Scala major version your use, and thereby fetch the correct version of the library.