Konrad is passionate about the JVM, and the whole ecosystem that surrounds it. Lately he fell in love with Scala, but that doesn't mean he's not into Java or dynamic languages. Other than that, he?s a fan of automating every possible task and ridiculously long keyboard shortcuts. "After hours" he's still bound to programming - as a lead of the PolishJUG, the lead of the Google Developers Group Kraków and helping hand of Software Craftsmanship Kraków he's coding for fun and glory, speaking at conferences, or organising meetups ranging from small hackathons to big conferences like the annual GeeCON. In those rare times when he's not doing something code-related, he's collecting game consoles or playing tennis / squash. He bloggs and tweets. Konrad is a DZone MVB and is not an employee of DZone and has posted 12 posts at DZone. You can read more from them at their website. View Full User Profile

Easily Cross-compile and Release Scala Projects With sbt

10.19.2012
| 2203 views |
  • submit to reddit

Scala’s lack of compatibility

Ok, lets get over with it – Scala is not binary compatible between minor versions (Where by minor I mean: MAJOR.MINOR.UPDATE). This raises the obvious problem that users of your library may be spread among 2.9.2 and 2.10.0 for example. And while your library would work fine with any of those versions, you’ll need to recompile and republish it two times – for those users.

Sounds like a pain, doesn’t it? Well, it is. The Scala ecosystem is currently fighting this problem with stabilizing scala itself, and libraries do released way quicker for new scala releases than before. Let’s see how we can bring my scala-rainbow library to new users with as little pain as possibe, shall we?

The goal is:

  • Compile the project using 2 (or more) scala versions,
  • Deploy all to the Sonatype OSS repository,
  • do all this using just one command.

Prepare sbt plugins

There are some plugins we’ll need to pimp sbt with in order to achieve our goal. The fist one is xsbt-gpg-plugin which gives us access to GPG from within SBT. Adding it to the project (or global settings) is as simple as adding those lines to project/plugins.sbt (mind the blank lines, they’re important – really):

// plugins.sbt
    resolvers += Resolver.url("sbt-plugin-releases",
      new URL("http://scalasbt.artifactoryonline.com/scalasbt/sbt-plugin-releases/"))(Resolver.ivyStylePatterns)
     
    addSbtPlugin("com.jsuereth" % "xsbt-gpg-plugin" % "0.6")

Next you’ll want to generate your pgp key, that we’ll use to sign your the library JAR’s (Sonatype requires us to do so). You can either follow the plugin’s way of doing this, as explained here or do it the GPG way which is really well described on this ubuntu manual page.

After you’ve created your key, and uploaded the public key, make sure that the “asc” (read up on the ubuntu manual about this) version of the key is located (or symlinked) in:

~/.sbt/gpg/my_funky_key.asc

As this is the place the sbt gpg plugin will look for keys to sign your JARs with.

Cross compilation

Next you should prepare sbt for cross compilation. I tend to prepare such settings in a separate value, which I use in all Project’s next. So you’d end up with a setting like this:

// Build.scala
    val buildSettings = Defaults.defaultSettings ++ Seq(
      organization := "pl.project13.scala",
      name := "rainbow",
      version := "0.1",
      scalaVersion := "2.10.0-M3",
      crossScalaVersions := Seq("2.9.1", "2.9.2", "2.10.0-M3"),
      libraryDependencies ++= dependencies
    )

Notice how right next to the typical “scalaVersion” setting, we’re using “crossScalaVersions”, where we define which other Scala versions this library should be compiled and released with. This is going to be used while the package, as well as publish commands.

The above buildSettings are used like this in your Project (in case you’ve forgotten):

// Build.scala
     
    lazy val root = Project (
      "rainbow",
      file("."),
      settings = buildSettings ++ sonatypeSettings ++
        Seq(/*…*/)
    )

Where sonatypeSettings is a bit of XML boilerplate, containing things like your SCM url, license and so on. If you’re stuck with building up your Build.scala, take a look at Build.scala from scala-rainbow, as it’s “as simple as it gets” :-)

In terms of Sonatype configuration just take a look at this wiki page what you’ll need to set up – or just refer to the above linked Build.scala. I won’t get more into detail about that, as it has been covered very well in the internet already, not as much as cross building… :-)

Let’s cross compile + publish!

They key element of this paragraph has already been spoiled a bit by it’s title. The command we’ll use to perform all 3steps needed to deploy our library, for 3 Scala versions to sonatype is…

+ publish

The plus before the command means “for all scala versions”, you can read more about Cross Building on the SBT wiki page about it.

And as a small apetizer, here’s how the output will look (trimmed down ;-)):

# example output
> + publish
  Setting version to 2.9.1
  …
  [success] Total time: 0 s, completed Sep 27, 2012 12:16:52 AM   
  Setting version to 2.9.2
  …
  [success] Total time: 2 s, completed Sep 27, 2012 12:16:54 AM
  Setting version to 2.10.0-M3
  …
  [success] Total time: 0 s, completed Sep 27, 2012 12:16:54 AM
  Setting version to 2.10.0-M3
  >

So as you can see – just one command, but it triggered for all Scala versions, and SBT took care of all scala version switching and executing of those tasks.

Having that said… It’s really easy nowadays to cross compile your projects to support multiple Scala versions. If you’re coding a library – be sure to include these configurations in your Build!

Published at DZone with permission of Konrad Malawski, author and DZone MVB. (source)

(Note: Opinions expressed in this article and its replies are the opinions of their respective authors and not those of DZone, Inc.)