How can I cross compile only 1 subproject in sbt? - scala

I have a multi-project sbt build using Build.scala.
I want to cross-compile one subproject against Scala 2.12 and 2.11, but the other subprojects have dependencies that don't support 2.12 yet, so I just want 2.11.
How can I do this in sbt?
I've tried this:
val scalaVer = "2.11.8"
val scalaVer12 = "2.12.0"
lazy val basicSettings = Seq(
scalaVersion := scalaVer
)
lazy val root = (project in file("."))
.settings(basicSettings: _*)
.aggregate(scalajack, scalajack_dynamodb, scalajack_mongo)
lazy val scalajack = project.in(file("core"))
.settings(basicSettings: _*)
.settings(Seq(crossScalaVersions := Seq(scalaVer, scalaVer12)))
lazy val scalajack_dynamodb = project.in(file("dynamodb"))
.settings(basicSettings: _*)
.dependsOn( scalajack )
lazy val scalajack_mongo = project.in(file("mongo"))
.settings(basicSettings: _*)
.dependsOn( scalajack )
This will build everything correctly but ignores my wish to have a 2.12 version of 'core' subproject.
I build packages with:
sbt> + package

Related

how to run scala sbt-native-packager for a appJS/appJVM cross-build project

The sbt-native-packager can make a zip file with all dependencies and a script to run_
$ sbt universal:packageBin
I have a scala web application, using cross-build (appJS for front-end and appJVM for back-end).
How do I run this packager for the appJVM?
I've tried as follows, but it does not accept the command:
$ sbt appJVM/universal:packageBin
Here it is the build.sbt project, from https://www.scala-js.org/doc/project/cross-build.html
...
lazy val foo = crossProject.in(file(".")).
settings(
name := "foo",
version := "0.1-SNAPSHOT"
).
jvmSettings(
// Add JVM-specific settings here
).
jsSettings(
// Add JS-specific settings here
)
lazy val fooJVM = foo.jvm
lazy val fooJS = foo.js
How do I run this packager for the appJVM?
And how I include the file generated by sbt appJS/fullOptJS?
And some other static files?
Update with Ivan response
build.sbt:
import sbtcrossproject.CrossPlugin.autoImport.{crossProject, CrossType}
val sharedSettings = Seq(
scalaVersion := "2.12.8",
)
lazy val app =
crossProject(JSPlatform, JVMPlatform)
.in(file("."))
.settings(sharedSettings)
.jsSettings(
)
.jvmSettings(
libraryDependencies ++= Seq(
"com.typesafe.akka" %% "akka-http" % "10.1.9"
),
)
lazy val backend = project
.enablePlugins(UniversalPlugin)
.enablePlugins(JavaAppPackaging)
.dependsOn(app.jvm)
.settings(
mainClass in Compile := Some("com.example.EchoServer")
)
lazy val frontend = project
.enablePlugins(ScalaJSPlugin)
.dependsOn(app.js)
backend
.settings(
Seq(
resourceGenerators in Compile += Def.task {
Seq(
(fullOptJS in Compile in frontend).value,
(fastOptJS in Compile in frontend).value
).map { js =>
val resource = (resourceManaged in Compile).value / "public" / "assets" / js.data.name
IO.write(resource, IO.read(js.data))
resource
}
}.taskValue
)
)
and run:
$ sbt backend/universal:packageBin
34: error: type mismatch;
found : Seq[sbt.Def.Setting[Seq[sbt.Task[Seq[java.io.File]]]]]
required: Int
Seq(
^
[error] Type error in expression
I used the following structure.
Define a shared project that needs to be cross-compiled for JS and Scala.
lazy val shared = CrossPlugin.autoImport
.crossProject(JSPlatform, JVMPlatform)
.crossType(CrossType.Pure)
.jvmSettings(???)
.jsSettings(???)
lazy val sharedJvm = shared.jvm
lazy val sharedJs = shared.js
Add project that contains a Main class.
lazy val backend = project
.enablePlugins(UniversalPlugin)
.enablePlugins(JavaAppPackaging)
.dependsOn(sharedJvm)
Add web project containing web related code.
lazy val web = project
.enablePlugins(ScalaJSPlugin)
.dependsOn(sharedJs)
And finally, attach resources from web compiled into JS to backend.
backend
.settings(
Seq(
resourceGenerators in Compile += Def.task {
Seq(
(fullOptJS in Compile in web).value,
(fastOptJS in Compile in web).value
).map { js =>
val resource = (resourceManaged in Compile).value / "public" / "assets" / js.data.name
IO.write(resource, IO.read(js.data))
resource
}
}.taskValue
)
Main class needs to service compiled JS from public/assets, as configured in sbt, and any other web resources from its class path.

How to run main project with all sub-project in scala SBT

I'm using multi-project build in SBT to create a simple microservice architecture. I defined build.sbt as:
addCommandAlias("rebuild", ";clean; compile; package")
lazy val oc = Project(id = "oc",
base = file("."),
settings = commonSettings).aggregate(
persistence,
core,
configuration,
integration).dependsOn(
persistence,
core,
configuration,
integration)
.configs (MultiJvm)
lazy val persistence = Project(...)
lazy val core = Project(...)
lazy val log = Project(...)
lazy val configuration = Project(...)
lazy val integration = Project(...)
lazy val commonSettings = Defaults.coreDefaultSettings ++
basicSettings ++
net.virtualvoid.sbt.graph.Plugin.graphSettings
lazy val basicSettings = Seq(
version := PROJECT_VERSION,
organization := ORGANIZATION,
scalaVersion := SCALA_VERSION,
scalacOptions in Compile ++= Seq("-deprecation", "-feature", "-unchecked", "-Xlog-reflective-calls", "-Xlint" , "-encoding", "utf8"),
javacOptions in Compile ++= Seq("-Xlint:unchecked", "-Xlint:deprecation"),
javaOptions in run ++= Seq("-Xms128m", "-Xmx1024m"),
libraryDependencies ++= Seq( ...
),
fork in run := true,
// disable parallel tests
parallelExecution in Test := false,
licenses := Seq(("CC0", url("http://creativecommons.org/publicdomain/zero/1.0"))),
fork in Test := true
)
For single sub-project I can easily build the project. But I cannot build all projects at once to check the working as a whole system. Any help from the experts on building the system would be appreciable

SBT/Scala: macro implementation not found

I tried my hand on macros, and I keep running into the error
macro implementation not found: W
[error] (the most common reason for that is that you cannot use macro implementations in the same compilation run that defines them)
I believe I've set up a two pass compilation with the macro implementation being compiled first, and the usage second.
Here is part of the /build.sbt:
lazy val root = (project in file(".")).
settings(rootSettings: _*).
settings(name := "Example").
aggregate(macros, core).
dependsOn(macros, core)
lazy val macros = (project in file("src/main/com/example/macros")).
settings(macrosSettings: _*).
settings(name := "Macros")
lazy val core = (project in file("src/main/com/example/core")).
settings(coreSettings: _*).
settings (name := "Core").
dependsOn(macros)
lazy val commonSettings = Seq(
organization := Organization,
version := Version,
scalaVersion := ScalaVersion
)
lazy val rootSettings = commonSettings ++ Seq(
libraryDependencies ++= commonDeps ++ rootDeps ++ macrosDeps ++ coreDeps
)
lazy val macrosSettings = commonSettings ++ Seq(
libraryDependencies ++= commonDeps ++ macrosDeps
)
lazy val coreSettings = commonSettings ++ Seq(
libraryDependencies ++= commonDeps ++ coreDeps
)
The macro implementation looks like this:
/src/main/com/example/macros/Macros.scala
object Macros {
object Color {
def ColorWhite(c: Context): c.Expr[ObjectColor] = c.Expr[ObjectColor](c.universe.reify(ObjectColor(White())).tree)
}
}
The usage looks like this:
/src/main/com/example/core/Main.scala
object Macros {
import com.example.macros.Macros._
def W: ObjectColor = macro Color.ColorWhite
}
object Main extends App {
import Macros._
println(W)
}
Scala 2.11.6. SBT 0.13.8.
What am I doing wrong?
Thanks for your advice!
Fawlty Project:
The Project on Github
Working Project:
Rearranged the projects to a more correct form:
The cleanedup working project
Your macros and core projects don't contain any files, so they don't cause the problem. The error happens when sbt compiles root, which contains both Main.scala and Macros.scala by the virtue of you saying project in file(".") in the sbt build.

How create sbt template for projects?

I have an sbt build with 2 duplicated projects configuration. See example:
lazy val MyProjectOne = Project(id = "OneId", base = file("path/OneId"))
.dependsOn(moduleOne)
.settings(plugin.settings: _*)
.settings(defaultSettings: _*)
.settings(webSettings: _*)
.settings(libraryDependencies ++= commonTests)
lazy val MyProjectTwo = Project(id = "TwoId", base = file("path/TwoId"))
.dependsOn(moduleOne)
.settings(plugin.settings: _*)
.settings(defaultSettings: _*)
.settings(webSettings: _*)
.settings(libraryDependencies ++= commonTests)
It is obvious that MyProjectOne and MyProjectTwo differs only in id and base properties.
Is there a way to refactor sbt build like this:
lazy val template = Project()
.dependsOn(moduleOne)
.settings(plugin.settings: _*)
.settings(defaultSettings: _*)
.settings(webSettings: _*)
.settings(libraryDependencies ++= commonTests)
//Just as example:
lazy val MyProjectOne = Project(id = "OneId", base = file("path/OneId")).extends(template)
lazy val MyProjectTwo = Project(id = "TwoId", base = file("path/TwoId")).extends(template)
How can I do that with sbt?
Also
With maven I can define a parent project pom for that case. Is there analog in sbt?

SBT: How to make one task depend on another in multi-project builds, and not run in the root project?

For my multi-project build, I'm trying to create a verify task that just results in scct:test and then scalastyle being executed in order. I would like scct:test to execute for all the subprojects, but not the top-level project. (If it executes for the top-level project, I get "timed out waiting for coverage report" from scct, since there's no source and no tests in that project.) What I had thought to do was to create verify as a task with dependencies on scct:test and scalastyle. This has turned out to be fairly baroque. Here is my Build.scala from my top-level project/ directory:
object MyBuild extends Build {
val verifyTask = TaskKey[Unit]("verify", "Compiles, runs tests via scct:test and then runs scalastyle")
val scctTestTask = (test in ScctPlugin.Scct).scopedKey
val scalastyleTask = PluginKeys.scalastyleTarget.scopedKey
lazy val root = Project("rootProject",
file("."),
settings = Defaults.defaultSettings ++
ScalastylePlugin.Settings ++
ScctPlugin.instrumentSettings ++
ScctPlugin.mergeReportSettings ++
Seq(
verifyTask in Global := {},
verifyTask <<= verifyTask.dependsOn(scctTestTask, scalastyleTask)
)
) aggregate(lift_webapp, selenium_tests)
lazy val subproject_1 = Project(id = "subproject_1", base = file("subproject_1"))
lazy val subproject_2 = Project(id = "subproject_2", base = file("subproject_2"))
}
However, the verify task only seems to exist for the root project; when I run it I don't see the same task being run in the subprojects. This is exactly the opposite of what I want; I'd like to issue sbt verify and have scct:test and scalastyle run in each of the subprojects but not in the top-level project. How might I go about doing that?
solution 1: define verifyTask in subprojects
First thing to note is that if you want some task (verify, test, etc) to run in some projects, you need to define them scoped to the subprojects. So in your case, the most straightforward thing to do this is to define verifyTask in subproject_1 and subproject_2.
lazy val scalaTest = "org.scalatest" %% "scalatest" % "3.0.4"
lazy val verify = taskKey[Unit]("verify")
def verifySettings = Seq(
skip in verify := false,
verify := (Def.taskDyn {
val sk = (skip in verify).value
if (sk) Def.task { println("skipping verify...") }
else (test in Test)
}).value
)
lazy val root = (project in file("."))
.aggregate(sub1, sub2)
.settings(
verifySettings,
scalaVersion in ThisBuild := "2.12.4",
skip in verify := true
)
lazy val sub1 = (project in file("sub1"))
.settings(
verifySettings,
libraryDependencies += scalaTest % Test
)
lazy val sub2 = (project in file("sub2"))
.settings(
verifySettings,
libraryDependencies += scalaTest % Test
)
solution 2: ScopeFilter
There was a recent Reddit thread that mentioned this question, so I'll post what I've done there.
If you want to manually aggregate on some subprojects, there's also a technique called ScopeFilter.
Note that I am using sbt 1.x here, but it should work with sbt 0.13 some minor change.
lazy val packageAll = taskKey[Unit]("package all the projects")
lazy val myTask = inputKey[Unit]("foo")
lazy val root = (project in file("."))
.aggregate(sub1, sub2)
.settings(
scalaVersion in ThisBuild := "2.12.4",
packageAll := {
(packageBin in Compile).all(nonRootsFilter).value
()
},
myTask := {
packageAll.value
}
)
lazy val sub1 = (project in file("sub1"))
lazy val sub2 = (project in file("sub2"))
def nonRootsFilter = {
import sbt.internal.inc.ReflectUtilities
def nonRoots: List[ProjectReference] =
allProjects filter {
case LocalProject(p) => p != "root"
case _ => false
}
def allProjects: List[ProjectReference] =
ReflectUtilities.allVals[Project](this).values.toList map { p =>
p: ProjectReference
}
ScopeFilter(inProjects(nonRoots: _*), inAnyConfiguration)
}
In the above, myTask depends on packageAll, which aggregates (packageBin in Compile) for all non-root subprojects.
sbt:root> myTask
[info] Packaging /Users/xxx/packageall/sub1/target/scala-2.12/sub1_2.12-0.1.0-SNAPSHOT.jar ...
[info] Done packaging.
[info] Packaging /Users/xxx/packageall/sub2/target/scala-2.12/sub2_2.12-0.1.0-SNAPSHOT.jar ...
[info] Done packaging.
[success] Total time: 0 s, completed Feb 2, 2018 7:23:23 PM
I may be wrong, but you are defining the verify task dependency only for the current project.
Maybe you can try:
Seq(
verifyTask in Global := {},
verifyTask <<= (verifyTask in Global).dependsOn(scctTestTask, scalastyleTask)
)
Or you can add the verifyTask settings to all your modules.