joslinm
joslinm

Reputation: 8105

Running a sub-project main class

I have a built.sbt that references a child project's main class as its own main class:

lazy val akka = (project in file("."))
  .aggregate(api)
  .dependsOn(api)
  .enablePlugins(JavaAppPackaging)

lazy val api = project in file("api")

scalaVersion := "2.11.6"

// This is referencing API code 
mainClass in (Compile, run) := Some("maslow.akka.cluster.node.ClusterNode")

artifactName := { (sv: ScalaVersion, module: ModuleID, artifact: Artifact) =>
  s"""${artifact.name}.${artifact.extension}"""
}

name in Universal := name.value

packageName in Universal := name.value

However, each time I run sbt run I get the following error:

> run
[info] Updating {file:/Users/mark/dev/Maslow-Akka/}api...
[info] Resolving jline#jline;2.12.1 ...
[info] Done updating.
[info] Updating {file:/Users/mark/dev/Maslow-Akka/}akka...
[info] Resolving jline#jline;2.12.1 ...
[info] Done updating.
[info] Running maslow.akka.cluster.node.ClusterNode
[error] (run-main-0) java.lang.ClassNotFoundException: maslow.akka.cluster.node.ClusterNode
java.lang.ClassNotFoundException: maslow.akka.cluster.node.ClusterNode
    at java.lang.ClassLoader.findClass(ClassLoader.java:530)

As I've been doing some research into the problem, I first switched to the project to api from akka and then opened up console. From there, it can't find the maslow package even though it most certainly exists. After that, I went into the api folder and ran sbt console and it accessed the aforementioned package just fine. After I do this, sbt run from the akka project works. Why?

The folder api is pulled in via git read-tree. There shouldn't be anything special about it. I'm using sbt 0.13.5

Upvotes: 0

Views: 1126

Answers (2)

joslinm
joslinm

Reputation: 8105

The problem was this line: lazy val api = project in file("api")

From the docs:

When defining a dependency on another project, you provide a ProjectReference. In the simplest case, this is a Project object. (Technically, there is an implicit conversion Project => ProjectReference) This indicates a dependency on a project within the same build.

This indicates a dependency within the same build. Instead, what I needed was to use RootProject since api is an external build:

It is possible to declare a dependency on a project in a directory separate from the current build, in a git repository, or in a project packaged into a jar and accessible via http/https. These are referred to as external builds and projects. You can reference the root project in an external build with RootProject:

In order to solve this problem, I removed the project declarations out of build.sbt into project/Build.scala:

import sbt._

object MyBuild extends Build {
  lazy val akka = Project("akka", file(".")).aggregate(api).dependsOn(api)
  lazy val api = RootProject(file("api"))
}

To be clear, the problem was that my api sub-project was a ProjectRef and not a RootProject.

Upvotes: 2

0__
0__

Reputation: 67280

I think in a multi-project build a global line such as

mainClass in (Compile, run) := ...

will just be swallowed without consequences, as it doesn't refer to any project.

Probably the following works:

mainClass in (Compile, run) in ThisBuild := ...

Or you add it to the root project's settings:

lazy val akka = (project in file("."))
  .aggregate(api)
  .dependsOn(api)
  .enablePlugins(JavaAppPackaging)
  .settings(
    mainClass in (Compile, run) := ...
  )

Upvotes: 2

Related Questions