how to declare and use object in this build.sbt? - scala

I am trying to understand how to write a well-written build.sbt file, and followed a tutorial on youtube. In that tutorial an object is created similar as below, but what I have written gives the shown error.
What am I doing wrong?
I have tried to remove blank lines between imports and the object declaration without any change.
import sbt._
import sbt.Keys._
object BuildScript extends Build {
lazy val commonSettings = Seq(
organization := "me",
version := "0.1.0",
scalaVersion := "2.11.4"
)
lazy val root = (project in file(".")).
settings(commonSettings: _*).
settings(
name := "deepLearning",
libraryDependencies += "org.deeplearning4j" % "deeplearning4j-core" % "0.4-rc3.4"
)}
error message:
error: illegal start of simple expression
object BuildScript extends Build {
^
[error] Error parsing expression. Ensure that there are no blank lines within a setting.
I think this thread actually explains it: What is the difference between build.sbt and build.scala?
I feel that the edit made by chris martin on this post was unnecessary, but can't reject it.

I think your tutorial was out of date. Using a recent version of sbt (0.13+ or so) you really want to do this:
lazy val commonSettings = Seq(
organization := "me",
version := "0.1.0",
scalaVersion := "2.11.4"
)
lazy val root = (project in file(".")).
settings(commonSettings).
settings(
name := "deepLearning",
libraryDependencies += "org.deeplearning4j" % "deeplearning4j-core" % "0.4-rc3.4"
)
If your project doesn't have any subprojects, though, the commonSettings val is somewhat superfluous, and you can just inline it:
lazy val root = (project in file(".")).
settings(
organization := "me",
name := "deepLearning",
version := "0.1.0",
scalaVersion := "2.11.4",
libraryDependencies += "org.deeplearning4j" % "deeplearning4j-core" % "0.4-rc3.4"
)
If you do have subprojects, and wind up with a lot of common settings, you may want to pull them out into an autoplugin, but that's a more advanced concept.

There are two ways to fix this:
Do object BuildScript extends Build { ... } and use .scala extension for the build file. I think this way is the recommended long term Sbt build file style.
Change build definition to gregsymons's answer and keep the .sbt extension.

Related

sbt - deep child modules

I'm new to sbt and I want to reproduce a complex project structure with many nested modules.
For example, I have the following structure:
.
build.sbt
|_web
|_api
|_dto
|_domain
build.sbt is as follows:
name := "myProject"
version := "1.0"
scalaVersion := "2.12.4"
resolvers += Resolver.sonatypeRepo("public")
libraryDependencies += "com.typesafe.play" %% "play" % "2.6.10"
lazy val commonSettings = Seq(
organization := "com.example",
version := "0.1",
scalaVersion := "2.12.4"
)
// root module
lazy val root = (project in file("."))
.aggregate(domain, web)
// domain module
lazy val domain = project.settings(commonSettings)
// web module
lazy val web = project.settings(
commonSettings,
libraryDependencies := Seq("com.typesafe.play" %% "play" % "2.6.10"),
name := "myproj-web"
).dependsOn(domain)
// web api module
lazy val webApi = (project in file("./web/api")).settings(
commonSettings,
libraryDependencies := Seq("com.typesafe.play" %% "play" % "2.6.10"),
name := "myproj-web-api"
).dependsOn(domain)
First problem I have is I can't access my libraries in web/api, though I can in web/.
Second problem is that I don't like file("./web/api"). Is it possible to make sbt understand nested folders as it understands plain folders (like web or domain).
Also, is it possible then to have build.sbt for each module. For example, for web to contain build file for api and dto, but preserving aggregations and ability to call build only on root project and have all the rest projects be built.

sscalaJSModuleKind := ModuleKind.CommonJSModule - cannot invoke main method anymore :(

I am trying to build a new facade that uses a lot of JSImport statements. I wanted to put it in a subfolder of a project I am currently working on, to improve it while at it.
Before my root build.sbt looked like this for the scala.js part:
lazy val client = (project in file("modules/client"))
.enablePlugins(ScalaJSPlugin, ScalaJSWeb)
.settings(generalSettings: _*)
.settings(
name := "client",
libraryDependencies += CrossDependencies.scalaTags,
persistLauncher := true
)
now I added this: scalaJSModuleKind := ModuleKind.CommonJSModule, which is incompatible with the persistLauncher setting, so I removed persistLauncher := true
Of course in my view I could no longer just add client-launcher.js. So I tried to wrap the main-method call manually, like this:
<script type="text/javascript">
tld.test.Test().main()
</script>
Now, this does NOT work IF scalaJSModuleKind := ModuleKind.CommonJSModule is added to my build.sbt. If I remove that setting everything works just fine.
This is my Test
package tld.test
import org.scalajs.dom
import scala.scalajs.js.JSApp
object Test extends JSApp
{
import scalatags.JsDom.all._
def main(): Unit =
{
// Add js script dynamically
val s = script(
"alert('Hello World!')"
)
dom.document.getElementsByTagName("head")(0).appendChild(s.render)
}
}
Now, if I remove that ModuleKind-setting an alert pops up with 'Hello World', but if it's there nope. What is causing this and how can I prevent it?
edit
After answer from #sjrd I tried the following:
plugins.sbt:
addSbtPlugin("ch.epfl.scala" % "sbt-scalajs-bundler" % "0.5.0")
addSbtPlugin("ch.epfl.scala" % "sbt-web-scalajs-bundler" % "0.5.0")
build.sbt:
lazy val client = (project in file("modules/client"))
.enablePlugins(ScalaJSBundlerPlugin, ScalaJSWeb) // ScalaJSBundlerPlugin automatically enables ScalaJSPlugin
.settings(generalSettings: _*)
.settings(
name := "client"
, libraryDependencies += CrossDependencies.scalaTags
//, scalaJSModuleKind := ModuleKind.CommonJSModule // ScalaJSBundlerPlugin implicitly sets moduleKind to CommonJSModule enables ScalaJSPlugin
)
lazy val server = (project in file("modules/server"))
.enablePlugins(PlayScala, WebScalaJSBundlerPlugin)
.settings(generalSettings: _*)
.settings(
name := "server"
,libraryDependencies ++= Seq(
CrossDependencies.scalaTest,
CrossDependencies.scalactic,
CrossDependencies.scalaTags,
"com.typesafe.play" %% "play-json" % "2.6.0-M1")
,scalaJSProjects := Seq(client)
,pipelineStages in Assets := Seq(scalaJSPipeline)
//,pipelineStages := Seq(digest, gzip)
,compile in Compile := ((compile in Compile) dependsOn scalaJSPipeline).value
)
But during compilation I get:
ERROR in ./fastopt-launcher.js
[info] Module not found: Error: Cannot resolve 'file' or 'directory' /home/sorona/scalajstestbed/modules/client/target/scala-2.12/scalajs-bundler/main/client-fastopt.js in /home/sorona/scalajstestbed/modules/client/target/scala-2.12/scalajs-bundler/main
edit: Solution is to then include client-fastopt-bundle.js et voila
Changing the module kind significantly changes the shape of the output file, include its external "specification". In particular, it is not a script that can be embedded in Web page anymore. Instead, it is a CommonJS module.
To be able to include it in a Web page, you will need to bundle it. The best way to do so is too use scalajs-bundler.

SBT: How to define dependencies of subprojects in subprojects' build.sbt files?

The following build.sbt file works, but it defines the dependencies of all subprojects:
name := "myproject"
version := "1.0"
scalaVersion := "2.11.8"
libraryDependencies ++= Seq(
"org.scalafx" %% "scalafx" % "8.0.60-R9"
)
lazy val aLib = (project in file("lib/a"))
lazy val bLib = (project in file("lib/b"))
.dependsOn(aLib)
.dependsOn(cLib)
lazy val cLib = (project in file("lib/c"))
.dependsOn(aLib)
lazy val myApp = (project in file("myapp"))
.dependsOn(aLib)
.dependsOn(bLib)
.dependsOn(cLib)
.aggregate(aLib, bLib, cLib)
Since each subproject (directories lib/a, lib/b, lib/c, myapp) has its own build.sbt file, I would like to use those build files to define the individual dependencies of each project.
I tried to move the dependsOn/aggregate statements to the subprojects' build files, but I am not able to make it work that way. What is the recommended way?

Project aggregation in sbt

I am just starting to learn sbt to build scala projects.
Here is my build.sbt file
lazy val commonSettings = Seq(
organization := "com.example",
version := "0.1.0",
scalaVersion := "2.11.7"
)
lazy val task = taskKey[Unit]("An example task")
lazy val root = project.in(file(".")).
aggregate(core).
settings(commonSettings: _*).
settings(
task := { println("Hello!") },
name := "hello",
version := "1.0"
)
lazy val core = project.in( file("SbtScalaProjectFoo") )
My project structure is as follows
SbtScalaProject
|--SbtScalaProjectFoo
|--build.sbt
|--build.sbt
When I try to run "sbt" inside SbtScalaProject I get the following
No project 'core' in 'file:/Users/asattar/Dev/work/SbtScalaProject/'
What am I missing?
Having multiple build.sbt's has proven to make problems for me, too.
I would recommend aggregating all project data into one build.sbt. If you want to modularize the build, consider moving parts into .scala-Files in (the root project's) project/ directory.

Adding module dependency information in sbt's build.sbt file

I have a multi module project in IntelliJ, as in this screen capture shows, contexProcessor module depends on contextSummary module.
IntelliJ takes care of everything once I setup the dependencies in Project Structure.
However, when I run sbt test with the following setup in build.sbt, I got an error complaining that it can't find the packages in contextSummary module.
name := "contextProcessor"
version := "1.0"
scalaVersion := "2.11.7"
libraryDependencies += "org.scalatest" % "scalatest_2.11" % "2.2.2" % "test"
How to teach sbt that the missing modules are found?
I could use the build.sbt file in the main root directory.
lazy val root = (project in file(".")).aggregate(contextSummary, contextProcessor)
lazy val contextSummary = project
lazy val contextProcessor = project.dependsOn(contextSummary)
Reference: http://www.scala-sbt.org/0.13.5/docs/Getting-Started/Multi-Project.html
For testing only one project, I can use project command in sbt.
> sbt
[info] Set current project to root (in build file:/Users/smcho/Desktop/code/ContextSharingSimulation/)
> project contextProcessor
[info] Set current project to contextProcessor (in build file:/Users/smcho/Desktop/code/ContextSharingSimulation/)
> test
For batch mode as in How to pass command line args to program in SBT 0.13.1?
sbt "project contextProcessor" test
I think a simple build.sbt might not be enough for that.
You would need to create a more sophisticated project/Build.scala like that:
import sbt._
import sbt.Keys._
object Build extends Build {
lazy val root = Project(
id = "root",
base = file("."),
aggregate = Seq(module1, module2)
)
lazy val module1 = Project(
id = "module1",
base = file("module1-folder"),
settings = Seq(
name := "Module 1",
version := "1.0",
scalaVersion := "2.11.7",
libraryDependencies += "org.scalatest" % "scalatest_2.11" % "2.2.2" % "test"
lazy val module2 = Project(
id = "module2",
base = file("module2-folder"),
dependencies = Seq(module1),
settings = Seq(
name := "Module 2",
version := "1.0",
scalaVersion := "2.11.7",
libraryDependencies += "org.scalatest" % "scalatest_2.11" % "2.2.2" % "test"
}