Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Scala SBT build multi module project to runnable jars

Tags:

scala

sbt

I am having problems building and running an SBT project.

  • The "protocol" project is used by several modules, including the "daemon".

  • The "daemon" project should be packaged as an executable jar.

What is the "right" way of doing this?

Here's my Build.scala:

object MyBuild extends Build {
lazy val buildSettings = Seq(
    organization := "com.example",
    version      := "1.0-SNAPSHOT",
    scalaVersion := "2.9.1"
    )

lazy val root = Project(
    id = "MyProject",
    base = file("."),
    aggregate = Seq(protocol, daemon)
    )

lazy val protocol = Project(
    id = "Protocol",
    base = file("Protocol")
    )

lazy val daemon = Project(
    id = "Daemon",
    base = file("Daemon"),
    dependencies = Seq(protocol)
    )
// (plus more projects)
like image 556
Arve Avatar asked Mar 19 '12 15:03

Arve


1 Answers

The right way to do this is to use one of the sbt plugins for producing jars. I've tested both one-jar and assembly and both have support for excluding libraries from your jar. You can add the settings to individual projects so that only some of them will produce jars.

I'm personally using assembly, but as this post points out, you will run into problems if you have overlapping filenames.

Edit:

For your example above you'd add the following imports at the top:

import sbtassembly.Plugin._ 
import AssemblyKeys._

You'd modify the project to look like this:

lazy val daemon = Project(
  id = "Daemon",
  base = file("Daemon"),
  dependencies = Seq(protocol),
  settings = assemblySettings
)

Also you need to add the following to your project/plugins.sbt (for sbt .11):

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

resolvers += Resolver.url("sbt-plugin-releases",
  new URL("http://scalasbt.artifactoryonline.com/scalasbt/sbt-plugin-releases/"))(Resolver.ivyStylePatterns)

If you decide to go with Assembly you'll probably need to remove duplicate files. Here's an example of the assembly code for excluding duplicate log4j.properties files in a project named "projectName". This should be added as part of the "settings" sequence for the project. Note that the 2nd collect statement is the base implementation and is required.

excludedFiles in assembly := { (bases: Seq[File]) =>
  bases.filterNot(_.getAbsolutePath.contains("projectName")) flatMap { base => 
    //Exclude all log4j.properties from other peoples jars
    ((base * "*").get collect {
      case f if f.getName.toLowerCase == "log4j.properties" => f
    }) ++ 
    //Exclude the license and manifest from the exploded jars
    ((base / "META-INF" * "*").get collect {
      case f if f.getName.toLowerCase == "license" => f
      case f if f.getName.toLowerCase == "manifest.mf" => f
    })
  }
}
like image 99
coltfred Avatar answered Sep 23 '22 10:09

coltfred