Search code examples
scalascala-3

build Windows EXE (or big jar) from scala-3 project


I have a Scala 3 project and need to build a binary which runs on machines where installing Java is possible, but I don’t want to install Scala there (because I want to be able to determine Scala versions solely on the dev side).

And I don’t want to build an installer file, because the file will get updated quite often.

I have a /src/main/scala/main.scala with

@main
def main(): Unit =

etc, and this is my build.sbt so far:

ThisBuild / version := "0.1.0-SNAPSHOT"

ThisBuild / scalaVersion := "3.3.1"

lazy val root = (project in file("."))
  .settings(
    name := "foo",
    libraryDependencies += "org.scala-lang.modules" %% "scala-parser-combinators" % "2.2.0",
    libraryDependencies += "org.scala-lang.modules" %% "scala-xml" % "2.1.0",
    libraryDependencies += "com.lihaoyi" %% "os-lib" % "0.9.1",
    libraryDependencies += "com.lihaoyi" %% "requests" % "0.8.0",
    libraryDependencies += "org.scalatest" %% "scalatest" % "3.2.15" % Test,
  )

scalacOptions ++= Seq("-deprecation", "-feature")

Is there an easy way to do this?


Solution

  • In the end, I used sbt-assembly to build a big jar. This way I still need Java at the target machine, but not Scala. At first I was not sure, because I could not find any version for Scala 3, but (as LuisMiguelMejíaSuárez pointed out) sbt plugins work with any (target) Scala version.

    I had to add a file project/plugins.sbt containing:

    addSbtPlugin("com.eed3si9n" % "sbt-assembly" % "2.1.5")
    

    And in build.sbt I configured the main class and target file name/location inside .settings( like this:

        assembly / mainClass := Some("main"),
        assembly / assemblyJarName := "../../foo.jar",
    

    I tried to use assemblyOutputPath instead of adding the path to assemblyJarName, but that deleted the whole project 😱, so I do not dare to use that again.

    sbt assembly builds the big jar and at the target machines I just do: java -jar foo.jar