How can I resolve dependencies when cross-compiling in Scala with sbt? - scala

I want to build a 2.11 and 2.12 version of my project, so I have something like this in my Build.scala file:
val scalaVer12 = "2.12.1"
val scalaVer = "2.11.8"
lazy val basicSettings = Seq(
// lots of other settings
scalaVersion := scalaVer
)
The fly in the soup is I have a dependency on scala reflection, which is based on the scala version. Before I did this:
val scala_reflect = "org.scala-lang" % "scala-reflect" % Build.scalaVer
How can I modify this dependency line so that sbt will use either the 2.11 or 2.12 dependency based upon the version it's currently building?

lazy val bla = project in file("bla")
.settings(
libraryDependencies ++= Seq(
"org.scala-lang" % "scala-reflect" % scalaVersion.value
)
)
Never alias dependencies like that, it's clean to have an object to store version numbers, but not more, it's just a smell, especially since deps are often Scala version dependent and you can apply all sorts of rules to them.

Related

maintain multi project modules with SBT

How to maintain multi module dependencies with Apache spark 2.3 in one module and Apache spark 2.4 in another one. What would be the project layer and how build.sbt looks like.
You can specify different dependencies for each module.
Let's assume you have module A and module B, it would look something like this:
lazy val moduleA = (project in file("moduleA"))
.settings(
name := "Module-A",
libraryDependencies ++= Seq("org.apache.spark" %% "spark-core" % "2.3.0")
)
lazy val moduleB = (project in file("moduleB"))
.settings(
name := "Module-B",
libraryDependencies ++= Seq("org.apache.spark" %% "spark-core" % "2.4.0")
)
The official documentation is pretty good, there are several examples

Can I create a proto jar for scalaVersion 2.11/2.12 and use it within the same sbt under different sub-project?

I have a set of .proto files (protobuf) which I generate java from using scalapb. I also have in the same sbt 2 sub-projects, one is scalaVersion 2.11 compatible (can't upgrade it to 2.12 due to missing packages) and the other one is scala 2.12.
I created a sub-project to hold my proto, and by default 2.12 is used and my 2.12 sub-project can use it, but my 2.11 can't.
I set the crossScalaVersions to 2.11/2.12, I compiled my project with both, which passed, but then even then I was unable to get the 2.11 sub-project to find that code.
I am "wondering" if that is something supported, or if there is a track I could use a single location to hold my .proto yet have my 2 sub-projects using the same sbt file use those.
lazy val scala212 = "2.12.13"
lazy val scala211 = "2.11.12"
lazy val supportedScalaVersion = List(scala212, scala211)
ThisBuild / scalaVersion := scala212
lazy val root = (project in file("."))
.aggregate(proto, subproject1, subproject2)
.settigns(
crossScalaVersions := Nil,
publish / skip := true
)
lazy val proto = project
.settings(
crossScalaVersions := supportedScalaVersions,
name := "proto",
libraryDependencies += "com.trueaccord.scalapb" %% "scalapb-runtime" % com.trueaccord.scalapb.compiler.Version.scalapbVersion % "protobuf",
PB.targets in Compile := Seq(
scalapb.gen(grpc = false) -> (sourceManaged in Compile).value / "protobuf"
)
)
lazy val subproject1 = project
.dependsOn(proto)
lazy val subproject2 = project
.settings(
scalaVersion := scala211
)
.dependsOn(proto)
So, from the above, if I do sbt "+ proto" I can compile both versions. If I do sbt subproject1/compile it works too. Using sbt subproject2/compile fails indicating that it cannot find the 2.11:proto jar file.
Either, I would like the above somehow to work nicely, or any other trick that I could generate the code from the same proto location but within subproject1/subproject2 would be appreciated.
You could try the sbt-projectmatrix plugin:
https://github.com/sbt/sbt-projectmatrix
The idea is to have separate sbt subprojects for the different Scala versions, so you can simply reference the relevant subproject when calling dependsOn.
I think this plugin is going to end up in sbt some day as it's a much better solution in general than the current built-in stateful cross compilation support, and it's developed by Eugene Yokota, who is also an sbt developer.

SBT multi module project: how to make static files (resources) available in main module?

I develop multi module SBT project. In general it's an akka api. It works well, when I run it locally and when I package it in docker.
Recently I added a new one module for email templates generation. I decided to use scalate mustache for this purpose. For a testing reason I created a simple template hello.mustache in email/src/main/resources/templates.
Then I run code which uses the template from the class located in email/src/main/scala. Everything compiled ok (scalate templates & scala code).
After I add a dependency to the email module to the security module which is included in app module:
import sbt.Keys._
import NativePackagerHelper._
lazy val core = project.in(file("core"))
.settings(name := "core")
.settings(Common.settings)
.settings(libraryDependencies ++= Dependencies.commonDependencies)
.enablePlugins(JavaAppPackaging)
lazy val email = project.in(file("email"))
.settings(name := "email")
.settings(Common.settings)
.settings(libraryDependencies ++= Dependencies.emailDependencies)
.enablePlugins(JavaAppPackaging)
lazy val contacts = project.in(file("contacts"))
.settings(name := "contacts")
.settings(Common.settings)
.dependsOn(core % "test->test;compile->compile")
.enablePlugins(JavaAppPackaging)
lazy val security = project.in(file("security"))
.settings(name := "security")
.settings(Common.settings)
.dependsOn(email, core % "test->test;compile->compile")
.enablePlugins(JavaAppPackaging)
lazy val app = project.in(file("."))
.enablePlugins(JavaAppPackaging, AshScriptPlugin, DockerPlugin)
.settings(name := "app")
.settings(Common.settings)
.dependsOn(core, security, contacts)
.settings(
mainClass in Compile := Some("com.app.Main"),
packageName in Docker := "app-backend",
version in Docker := "latest",
dockerBaseImage := "openjdk:8-jre-alpine",
dockerExposedPorts := Seq(5000)
)
I see the following errors, while trying to run the email code:
Exception in thread "main" org.fusesource.scalate.TemplateException: scala.tools.nsc.symtab.classfile.ClassfileParser$unpickler$.unpickle([BILscala/reflect/internal/Symbols$Symbol;Lscala/reflect/internal/Symbols$Symbol;Ljava/lang/String;)V
at org.fusesource.scalate.TemplateEngine.compileAndLoad(TemplateEngine.scala:886)
at org.fusesource.scalate.TemplateEngine.compileAndLoadEntry(TemplateEngine.scala:745)
...
How to make email module code work in another modules?
Additional info:
I try to run the code directly from IDE by run of the Main class from the app module.
Scala version 2.12.2; Scalate version 1.8.0; sbt version 0.13.8;
I'm afraid that you encountered a bin compatibility issues among several scala compiler versions. Explicitly overriding the scala lang version like this is preferred to avoid such problems.
dependencyOverrides := Set(
"org.scala-lang" % "scala-library" % scalaVersion.value,
"org.scala-lang" % "scala-reflect" % scalaVersion.value,
"org.scala-lang" % "scala-compiler" % scalaVersion.value
),
In my particular case there was a problem in a conflict of log4j version of scalate and one other scala lib. So the solution which works for me is:
"org.scalatra.scalate" %% "scalate-core" % "1.8.0" excludeAll(ExclusionRule(organization = "org.slf4j"))

Install scalatest in Scala IDE for Eclipse

I have installed Eclipse Luna. Then I installed Scala IDE via Help -> Install new software and adding software site with link from here. Then I installed sbt 0.13 and sbteclipse using this mini-guide and created eclipse project. Then I installed (kindda) scalatest by adding it to my build.sbt. Now it looks like this:
val scalaTest = "org.scalatest" % "scalatest_2.11" % "2.2.4" % "test"
lazy val commonSettings = Seq(
scalaVersion := "2.11.6"
)
lazy val root = (project in file(".")).
settings(commonSettings: _*).
settings(
libraryDependencies += scalaTest
)
Then I created a test from this example. The file called FirstSpec.scala is located in testProject/src/test/scala-2.11/testProject/. So here is a problem: eclipse seems to not see scalaTest. The second line with import org.scalatest._ is underlined red with error description object scalatest is not a member of package org. And, following this guide, I don't see the option Run As -> ScalaTest - Suite when choosing my test class.
At the same time everything goes good and fine when I start sbt session in my test project and type test command. The tests launches and passes.
So my questions are:
why eclipse doesn't see the scalatest if I put it in build.sbt's libraryDependencies? What's the point of libraryDependencies then?
Why sbt test runs the tests without a problem? If sbt sees scalatest, why eclipse can't?
Whew, this one resolved my issue. So, build.sbt example might go something like:
import com.typesafe.sbteclipse.plugin.EclipsePlugin._
EclipseKeys.withSource := true
val scalaTest = "org.scalatest" % "scalatest_2.11" % "2.2.4" % "test"
val jodaConvert = "org.joda" % "joda-convert" % "1.7"
val joda = "joda-time" % "joda-time" % "2.7"
lazy val commonSettings = Seq(
scalaVersion := "2.11.6"
)
lazy val root = (project in file(".")).
settings(commonSettings: _*).
settings(
libraryDependencies += scalaTest
).
settings(
libraryDependencies += jodaConvert
).
settings(
libraryDependencies += joda
)
Then do this:
rm -rf ~/.ivy2/cache/
sbt update-classifiers
sbt eclipse

Unable to add scala-reflect as a dependency

I can't add scala-reflect as dependency. My project/build.sbt looks like this:
//the name of the project, will become the name of the war file when you run the package command.
name := "Test-SBT"
version := "1.0"
//specify which Scala version we are using in this project.
scalaVersion := "2.10.3"
libraryDependencies <++= (scalaVersion)(sv =>
Seq(
"org.scala-lang" % "scala-reflect" % "2.10.3",
"org.scala-lang" % "scala-compiler" % "2.10.3"
)
)
And project/build.properties
sbt.version=0.13.0
And here is my Main class:
object Main1 extends App {
import scala.reflect.runtime.universe
val runtimeMirror = universe.runtimeMirror(getClass.getClassLoader)
//......
}
It says object runtime is not a member of package reflect. Of course, I did "gen-idea", "clean" and other things. What's up with that?
Guessing here due the question by #laughedelic.
The build.sbt should be in the root. Assuming the project you are writing is in test-sbt, you should end up with structure similar to:
test-sbt/build.sbt
test-sbt/project
Otherwise the build.sbt is used in creating the "internal compile project" used by SBT.
A deeper explanation can be found at SBT's docs sbt is recursive.