I'm trying to create a multi-project SBT build definition. I'm having trouble executing the run command on my root project.
The folder structure is the following:
RootProjectFolder
 |
 |- build.sbt
 |- project
       |
       |-Build.scala
       |-plugins.sbt
 |
 | - play-webapp
The contents of the Build.scala file is:
import sbt._
import Keys._
import play.Project._
object ApplicationBuild extends Build {
    val appName         = "project-name"
    val appVersion      = "0.1.0-SNAPSHOT"
    lazy val root = Project(id = appName + "-root", 
                            base = file(".")
                    ).aggregate(webApp)
    lazy val webApp = play.Project(
      appName + "-website", appVersion, path = file("play-webapp")
    )
}
When I launch SBT I get the following message: Set current project to project-name-root which implies that the root project was detected correctly.
When I execute the run command I get the following error message
> run
java.lang.RuntimeException: No main class detected.
        at scala.sys.package$.error(package.scala:27)
[trace] Stack trace suppressed: run last project-name-root/compile:run for the full output.
[error] (project-name-root/compile:run) No main class detected.
The error message is correct in saying that the root project does not have any classes, but the play-webapp project has. I assumed that the result would be to run the play app.
If I type project play-webapp before run everything seems to be ok.
Is this the correct behavior? Or am I doing something wrong?
P.S. I'm using SBT version 0.13 and scala version 2.10.3
Another way is to redefine run:
lazy val root = Project("root", file("."))
  .aggregate(subproject)
  .settings(
      run := {
        (run in subproject in Compile).evaluated
      }
    )
lazy val subproject = Project(...)
I really wish I could explain it better, but it's only after lots of trial and error I have managed to find an answer. Expect a better explanation once I've learnt more.
tl;dr Add the following to RootProjectFolder/build.sbt (in 0.13 build.sbt can define multi-project setup):
mainClass in `project-name-root` in Compile := (mainClass in `play-webapp` in Compile).value
fullClasspath in `project-name-root` in Runtime ++= (fullClasspath in `play-webapp` in Runtime).value
Longer explanation (not necessarily complete and correct so use on your own risk).
I assume your multi-project configuration is as follows - run projects in the sbt shell.
[project-name-root]> projects
[info] In file:/Users/jacek/sandbox/stackoverflow/sbt-run/
[info]     play-webapp
[info]   * project-name-root
Change the project names below when required.
When you execute inspect run in sbt shell you'll notice that the run task depends on project-name-root/runtime:fullClasspath and project-name-root/compile:run::mainClass settings.
[project-name-root]> inspect run
[info] Input task: Unit
[info] Description:
[info]  Runs a main class, passing along arguments provided on the command line.
[info] Provided by:
[info]  {file:/Users/jacek/sandbox/stackoverflow/sbt-run/}project-name-root/compile:run
[info] Defined at:
[info]  (sbt.Defaults) Defaults.scala:688
[info] Dependencies:
[info]  project-name-root/compile:run::streams
[info]  project-name-root/runtime:fullClasspath
[info]  project-name-root/compile:run::runner
[info]  project-name-root/compile:run::mainClass
[info] Delegates:
[info]  project-name-root/compile:run
[info]  project-name-root/*:run
[info]  {.}/compile:run
[info]  {.}/*:run
[info]  */compile:run
[info]  */*:run
[info] Related:
[info]  project-name-root/test:run
[info]  sub/compile:run
[info]  sub/test:run
Since I knew how to change the settings with the value of the sub project's settings, I used the := method for the value of the root project. It works fine, but am quite certain there are better ways to achieve it. I can't wait to find them out.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With