How to create an executable JAR file with `scalac` (and run it with `scala`)

If you’re ever working on a really small Scala project — something that contains only a few source code files — and don’t want to use SBT to create a JAR file, you can do it yourself manually. Let’s look at a quick example. Note that the commands below work on Mac and Linux systems, and should work on Windows with minor changes.

Back to top

Example

Given a file named Hello.scala with these contents:

object Hello extends App {
    println("Hello, world")
}

you can compile that source code file directly to a JAR file like this:

$ scalac Hello.scala -d Hello.jar

That creates Hello.jar, whose contents you can look at like this:

$ jar tvf Hello.jar
    76 Mon Apr 15 18:45:56 MDT 2019 META-INF/MANIFEST.MF
  2554 Mon Apr 15 18:45:56 MDT 2019 Hello$.class
   753 Mon Apr 15 18:45:56 MDT 2019 Hello.class
   751 Mon Apr 15 18:45:56 MDT 2019 Hello$delayedInit$body.class

The META-INF/MANIFEST.MF file contains these contents:

Manifest-Version: 1.0
Scala-Compiler-Version: 2.12.8
Main-Class: Hello

Now you can run/execute the JAR file with the scala command like this:

$ scala Hello.jar

That produces the expected output:

Hello, world

That’s all there is to it. The key to this solution is knowing that the scalac “-d” option can be used to create an executable JAR fie.

Back to top

A more complex example

As a more complicated example I just did a similar thing by creating a one-object application that relies on two JAR files. The commands I used are the same, except for adding in the classpath complexity. Assuming I start with a Scala source code file named Foo.scala and want to create a JAR file named Foo.jar, the scalac command to create the JAR file looks like this:

$ scalac -classpath "sed_2.12-0.1.jar:kaleidoscope_2.12-0.1.0.jar" Foo.scala -d Foo.jar

I can then run the application with the scala command like this:

$ scala -classpath "sed_2.12-0.1.jar:kaleidoscope_2.12-0.1.0.jar:Foo.jar" Foo

I should mention that the Foo.scala file has source code that begins like this:

object Foo extends App ...

It’s not in a package, so I refer to Foo at the end of the scala command (as opposed to something like my.package.Foo).

Back to top

Note

Some people have written to say that this technique didn’t work for them. It worked on several examples for me, and today (May 12, 2019) I had my first problem with it. My problem seems to be that it generated an empty META-INF/MANIFEST.MF file. I tried a couple of things to get this to work, but I’m out of time for today; I’ll work on it again when I have more time.

Back to top

Summary

If you ever need to create a JAR file with scalac and then run that JAR file with scala, I hope these examples are helpful.

Back to top