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:
As this is the place the sbt gpg plugin will look for keys to sign your JARs with.
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…
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!