SBT Run Main Method from a Sub Project - scala

I am writing a project which contains scala macros. This is why I have organized my project into two sub projects called "macroProj" and "coreProj". The "coreProj" depends on "macroProj" and also contains the main method to run my code.
My requirement is that when I do a sbt run from the root project, the main method is taken from the coreProj sub project. I search and found a thread which has a solution for this
sbt: run task on subproject
Based on this my build.sbt looks like
lazy val root = project.aggregate(coreProj,macroProj).dependsOn(coreProj,macroProj)
lazy val commonSettings = Seq(
scalaVersion := "2.11.7",
organization := "com.abhi"
)
lazy val coreProj = (project in file("core"))
.dependsOn(macroProj)
.settings(commonSettings : _*)
.settings(
mainClass in Compile := Some("demo.Usage")
)
lazy val macroProj = (project in file("macro"))
.settings(commonSettings : _*)
.settings(libraryDependencies += "org.scala-lang" % "scala-reflect" % scalaVersion.value)
mainClass in Compile <<= (run in Compile in coreProj)
But when I do sbt run from the root directory. I get an error
/Users/abhishek.srivastava/MyProjects/sbt-macro/built.sbt:19: error: type mismatch;
found : sbt.InputKey[Unit]
required: sbt.Def.Initialize[sbt.Task[Option[String]]]
mainClass in Compile <<= (run in Compile in coreProj)
^
[error] Type error in expression

In sbt, mainClass is a task that will return an entry point to your program, if any.
What you want to do is to have mainClass be the value of mainClass in coreProj.
You can achieve that this way:
mainClass in Compile := (mainClass in Compile in coreProj).value
This could also be achieved with
mainClass in Compile <<= mainClass in Compile in coreProj
However, the preferred syntax is (...).value since sbt 0.13.0.

Related

SBT error: "Runtime reference to undefined setting"

I am trying to reference another Github project as a build dependency in sbt using the following code that sits in build.sbt:
lazy val dependency = RootProject(uri("..."))
// The Play project itself
lazy val root = (project in file("."))
.enablePlugins(Common, PlayScala, GatlingPlugin)
.configs(GatlingTest)
.settings(inConfig(GatlingTest)(Defaults.testSettings): _*)
.dependsOn(dependency)
.settings(
name := """play-scala-rest-api-example""",
scalaSource in GatlingTest := baseDirectory.value / "/gatling/simulation"
)
And I get the error:
Runtime reference to undefined setting:
[error]
[error] ProjectRef(uri("..."), "dependency")

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?

sbt-assembly does not pick up configuration specific settings

I am updating an old 0.7.x build file from the tool sbt that thankfully removed the reference to "simple" from its name in the meantime.
Something that once worked, does not do so any longer. I had different config entries for platform specific assembly tasks. These include specific filters that for some reason are now called assemblyExcludedJars instead of excludedJars, and specific jar names that for some reason are now called assemblyJarName instead of jarName.
Basically:
val Foo = config("foo") extend Compile
lazy val assemblyFoo = TaskKey[File]("assembly-foo")
lazy val root = Project(id = "root", base = file("."))
// .configs(Foo) // needed? doesn't change anything
.settings(
inConfig(Foo)(inTask(assembly) {
assemblyJarName := "wtf.jar"
}),
scalaVersion := "2.11.7",
assemblyFoo <<= assembly in Foo
)
Now I would expect that if I run sbt assembly-foo or sbt foo:assembly, it would produce a file wtf.jar. But I am getting the default root-assembly-0.1-snapshot.jar. The same problem happens when I try to specify assemblyExcludedJars, they are simply ignored and still included.
If I remove the inConfig it works:
lazy val root = Project(id = "root", base = file("."))
.settings(
inTask(assembly) {
assemblyJarName := "wtf.jar"
},
scalaVersion := "2.11.7",
assemblyFoo <<= assembly in Foo
)
But now I cannot use different jar names for different configurations (which is the whole point).
As described in a blog post by one of sbt's authors and the author of sbt-assembly, this should work. It was also written in this Stackoverflow question. But the example requires an antique version of sbt-assembly (0.9.0 from 2013, before auto plugins etc.) and doesn't seem to apply to the current versions.
If one defines a new configuration, one has to redefine (?) all the tasks one is about to use. Apparently for sbt-assembly, this means running baseAssemblySettings:
val Foo = config("foo") extend Compile
lazy val assemblyFoo = TaskKey[File]("assembly-foo")
lazy val root = Project(id = "root", base = file("."))
.settings(
inConfig(Foo)(baseAssemblySettings /* !!! */ ++ inTask(assembly) {
jarName := "wtf.jar"
}),
scalaVersion := "2.11.7",
assemblyFoo := (assembly in Foo).value
)
Tested with sbt 0.13.9 and sbt-assembly 0.14.1.

How to generate links to standard library types in scaladoc?

I'm using sbt 0.13.7 and Scala 2.11.4.
In my build.sbt, I have:
autoAPIMappings := true
and in a File.scala:
/** scaladoc link to [[scala.concurrent.duration.FiniteDuration]] */
When running sbt doc, I’m getting:
[warn] ...:5: Could not find any member to link for "scala.concurrent.duration.FiniteDuration".
[warn] /** scaladoc link to [[scala.concurrent.duration.FiniteDuration]] */
[warn] ^
Now, when I replace autoAPIMappings := true with:
apiMappings += (scalaInstance.value.libraryJar ->
url(s"http://www.scala-lang.org/api/${scalaVersion.value}/"))
the compiler still gives the warning.
What could be a solution?
I wasn't able to reproduce this behavior using sbt 0.13.7 and Scala 2.11.4.
Do you have multi-project setup? If so make sure to explicitly add settings to each project, or define the common settings in ThisBuild scope.
project/build.properties
sbt.version=0.13.7
build.sbt
lazy val commonSettings = Seq(
scalaVersion := "2.11.4",
autoAPIMappings := true
)
lazy val root = (project in file(".")).
aggregate(app).
settings(commonSettings: _*)
lazy val app = (project in file("app")).
settings(commonSettings: _*)
src/main/scala/Hello.scala
/** scaladoc link to [[scala.concurrent.duration.FiniteDuration]] */
object Hello extends App {
}

How to have sbt multi-project builds configure setting for subprojects?

I have an sbt (0.13.1) project with a bunch of subprojects. I am generating eclipse project configurations using sbteclipse. My projects only have scala source files, so I want to remove the generated src/java folders.
I can achieve that by (redundantly) adding the following to the build.sbt of each subproject:
unmanagedSourceDirectories in Compile := (scalaSource in Compile).value :: Nil
unmanagedSourceDirectories in Test := (scalaSource in Test).value :: Nil
I tried just adding the above configuration to the root build.sbt but the eclipse command still generated the java source folders.
Is there any way to specify a configuration like this once (in the root build.sbt) and have it flow down to each subproject?
You could define the settings unscoped and then reuse them
val onlyScalaSources = Seq(
unmanagedSourceDirectories in Compile := Seq((scalaSource in Compile).value),
unmanagedSourceDirectories in Test := Seq((scalaSource in Test).value)
)
val project1 = project.in( file( "project1" )
.settings(onlyScalaSources: _*)
val project2 = project.in( file( "project2" )
.settings(onlyScalaSources: _*)
You could also create a simple plugin (untested code)
object OnlyScalaSources extends AutoPlugin {
override def trigger = allRequirements
override lazy val projectSettings = Seq(
unmanagedSourceDirectories in Compile := Seq((scalaSource in Compile).value),
unmanagedSourceDirectories in Test := Seq((scalaSource in Test).value)
)
}
More details about creating plugins in the plugins documentation