Cannot specify main class for both running AND packaging jar in SBT 0.12.3 - scala

For some reason I cannot simultaneously specify main class for run and packaging jar in SBT 0.12.3.
The problem is that sbt publish-local doesn't put name of main class to jar's manifest if I don't set it explicitly.
But interestingly enough this
mainClass in (Compile,run) := Some("Hi")
and
mainClass in (Compile,packageBin) := Some("Hi")
work separately but this
mainClass in (Compile,run,packageBin) := Some("Hi")
causes SBT fail with following error
C:\work\test_projects\hw\build.sbt:13: error: reassignment to val
mainClass in (run,Compile,packageBin) := Some("Hi")
^
[error] Type error in expression
Is it a bug or am I missing something ?

The (Compile,run) in
mainClass in (Compile,run) := Some("Hi")
is specifying the two axes of the four axes that a setting has, so (Compile,run,packageBin) doesn't make sense. If you want to grab the value from the other, you could say:
mainClass in (Compile,packageBin) <<= mainClass in (Compile,run)
For more details, check out Getting Started guide.

Related

Set mainClass for sbt native packager Universal

I have a project that has the following build.sbt:
addCommandAlias("package", "dist")
lazy val actual = (project in file("."))
.enablePlugins(UniversalPlugin, JavaServerAppPackaging)
.settings(
name := "DeployerPod",
mainClass := Some("com.myself.executable.Runner"),
Compile / mainClass := Some("com.myself.executable.Runner"),
Compile / run / mainClass := Some("com.myself.utils.Pipeline"),
Universal / mainClass := Some("com.myself.executable.Runner"),
Universal / compile / mainClass := Some("com.myself.executable.Runner"),
)
We have a CICD which runs a Dockerfile.
There I have sbt run as one of the steps, which will execute com.myself.utils.Pipeline class to run a Scala class and do the pre requisites for the pipeline.
As one of the last sbt based steps, I'm also running sbt package, which eventually runs an sbt dist command. At this point, inside the extracted ZIP's bin folder, I see two BAT files corresponding to the two main classes. Unfortunately I only want the Runner class BAT instead of Pipeline BAT.
For this I tried running sbt package -main com.myself.executable.Runner but that failed saying Not a valid command: -
Is there a way I can specify the mainClass only for this Universal plugin somehow? Because the way I've tried in my build.sbt doesn't seem to work.

sbt-native-packager defining multiple mainClasses in different modules

I would like to package multiple docker images, each one having its own mainClass, to ensure the app is running on startup.
lazy val `core` = project.in(file("core"))
.enablePlugins(JavaServerAppPackaging, DockerPlugin)
.settings{
mainClass in Compile := Some("path/to/Core") // Doesn't work
}
lazy val `benchmark` = project.in(file("benchmark"))
.enablePlugins(JavaServerAppPackaging, DockerPlugin)
.settings{
mainClass in Compile := Some("path/to/Benchmark") // Doesn't work
}
This does not work as the mainClasses are not found in the stage step.
When I define mainClass as a global parameter it works, but I can't build two auto-running Docker images this way.
Thanks for your help
I am not experienced with sbt-native-packager but mainClass is the classpath not the file path, so it must be defined as:
mainClass in (Compile, packageBin) := Some("com.bar.baz.Foo")

No main module initializer was specified (possibly because no or multiple main classes were found)

Using the following project structure:
project/build.properties:
sbt.version = 1.1.4
project/plugins.sbt:
addSbtPlugin("org.scala-js" % "sbt-scalajs" % "0.6.22")
build.sbt:
enablePlugins(ScalaJSPlugin)
name := "scalajs_example"
version := "0.1"
scalaVersion := "2.12.6"
and src/main/scala/my/Main.scala:
package my
class Main {
def main(args: Array[String]): Unit = {
println("Hello world")
}
}
I get the following error when executing sbt run:
[error] No main module initializer was specified (possibly because no
or multiple main classes were found), but
scalaJSUseMainModuleInitializer was set to true. You can explicitly
specify it either with mainClass := Some(...) or with
scalaJSMainModuleInitializer := Some(...) [error] (Compile /
scalaJSModuleInitializers) No main module initializer was specified
(possibly because no or multiple main classes were found), but
scalaJSUseMainModuleInitializer was set to true. You can explicitly
specify it either with mainClass := Some(...) or with
scalaJSMainModuleInitializer := Some(...)
Adding mainClass := Some("my.Main") to build.sbt and reloading the project did not help, same error remain when tried sbt run (scalaJSMainModuleInitializer := Some(...) - I could not figure out what to put to the ...).
The problem was with the using class Main instead of object Main. After the change, it works as expected:
[info] Running my.Main
Hello world
with or without explicitly specifying mainClass (it seems specifying an invalid main class will still find the only good one).

sbt deprecation warning <<= replaced with := results in no main class found

When using sbt 0.13.13. I could observe that when using := no main class is found (but no deprecation warning is shown), and for <<= I get the warning, but the main class is found. What is wrong here?
run in Compile := Defaults.runTask(fullClasspath in Compile, mainClass in(Compile, run), runner in(Compile, run))
run in Compile <<= Defaults.runTask(fullClasspath in Compile, mainClass in(Compile, run), runner in(Compile, run))
run is an InputTask[Unit] and the type of runTask is Def.Initialize[InputTask[Unit]] and the right side of := needs to be a Unit.
What you did compiles because any value can be discarded in favor of a return value of type Unit, but it doesn't have the same semantics as before.
For input tasks, you need to "evaluate" the task:
run in Compile := Defaults.runTask(
fullClasspath in Compile,
mainClass.in(Compile, run),
runner.in(Compile, run)).evaluated

Problems finding Main class in sub-directories w/SBT assembly

I am attempting to use SBT assembly(0.14.0) to create a fat jar of my Scala project.
My project structure is as follows:
>top
> build.sbt
> api
> src
> main
> scala
> name
> Boot.scala
> other directories
I am trying to set Boot as the main method to be run in the jar.
I have tried using:
baseDirectory in (Compile,run) := file("api")
scalaSource in run := baseDirectory.value / "api"
scalaSource in Compile := baseDirectory(_ / "api")
mainClass in assembly := some("name.Boot")
The jar builds successfully but when running it I receive the error:
Error: Could not find or load main class name.Boot
Going by the snippet you posted, you could try changing
mainClass in assembly := some("name.Boot")
to
mainClass in assembly := Some("name.Boot")
The reason it does not complain is that lower case some refers to something else.
The file path of your mainClass isn't relevant, only the namespace in Scala/Java. Is your main object
package name
object Boot {
def main ...
}
?