Thursday, January 27, 2011

Create an Executable Scala Jar with SBT

A friend was asking about building an executable Jar with Scala and SBT. This ended up working for me.

In a fresh SBT project, create the following files:

project/build/AssemblyProject.scala
(this file is lifted in its entirety from here - thanks to Nathan Hamblen)

import sbt._

trait AssemblyProject extends BasicScalaProject {
def assemblyExclude(base: PathFinder) = base / "META-INF" ** "*"
def assemblyOutputPath = outputPath / assemblyJarName
def assemblyJarName = artifactID + "-assembly-" + version + ".jar"
def assemblyTemporaryPath = outputPath / "assembly-libs"
def assemblyClasspath = runClasspath
def assemblyExtraJars = mainDependencies.scalaJars
def assemblyPaths(tempDir: Path, classpath: PathFinder, extraJars: PathFinder, exclude: PathFinder => PathFinder) = {
val (libs, directories) = classpath.get.toList.partition(ClasspathUtilities.isArchive)
for(jar <- extraJars.get ++ libs) FileUtilities.unzip(jar, tempDir, log).left.foreach(error)
val base = (Path.lazyPathFinder(tempDir :: directories) ##) (descendents(base, "*") --- exclude(base)).get }
lazy val assembly = assemblyTask(assemblyTemporaryPath, assemblyClasspath, assemblyExtraJars, assemblyExclude) dependsOn(compile)
def assemblyTask(tempDir: Path, classpath: PathFinder, extraJars: PathFinder, exclude: PathFinder => PathFinder) =
packageTask(Path.lazyPathFinder(assemblyPaths(tempDir, classpath, extraJars, exclude)), assemblyOutputPath, packageOptions)
}
project/build/Project.scala

import sbt._

class ExecutableProject(info: ProjectInfo) extends DefaultProject(info) with AssemblyProject {
override def mainClass = Some("RunMe")
}
src/main/scala/RunMe.scala

object RunMe {
def main(args: Array[String]) = {
println("I run.")
}
}
Now in your sbt shell, run:
reload
compile
assembly
That will create an executable jar in the target/scala_*version* directory. You can run it with something like:
java -jar target/scala_2.8.1/runme_2.8.1-assembly-1.0.jar
I run.
Thanks to Nathan Hamblen for the AssemblyProject trait.

2 comments:

  1. The sbt onejar plugin worked very well for me: https://github.com/retronym/sbt-onejar

    ReplyDelete
  2. The first file seems to have some formatting problems, with many statements on the same line.

    ReplyDelete