It’s the community, stupid.
If you have to pick, choose function over form (at least when it comes to build tools).
Ahem. Sorry, let’s start from the beginning.
Like any group of super-smart programmers using a relatively new language, a lot of folks in the Clojure community have looked at existing build tools (the JVM space is the relevant one here, meaning primarily Maven and Ant, although someone will bark if I don’t mention Gradle, too), and felt a rush of disdain. I’d speculate that this came mostly because of XML allergies, but perhaps also in part because when one has a hammer as glorious as Clojure, it’s hard to not want to use it to beat away at every problem in sight. Ruby has rake, and python has easy_install, so it seems natural that Clojure should have its own build system that leverages the language’s stellar capabilities – “just think of how simple builds could be given macros and such”, one might think.
I can sympathize with that perspective, and I admit that I, too, once thought that a Clojure-based build system was an obvious move. This notion runs off the rails pretty quickly for one reason:
Builds inherently involve stitching together lots of bits from disparate sources. Clojure is great for building amazingly flexible and featureful programs up from first principles, but don’t confuse that foundational capability with being able to easily deploy a Compojure web application to any of 12 app servers, or building Windows installers (or Windows executables, even), or tagging revisions in your SCM of choice, or easily using continuous integration servers like Hudson.
You can either help reimplement all of these things – or, if you’re lucky enough to have access to a build tool that has a community that has built all these things already, you can use that.
Handily enough, Clojure is a JVM language, so using all of the goodness that’s been built up over the years in Maven-land is extraordinarily easy to do. This means you have to write less code, and you get to use more mature, well-tested, well-supported code and tools, allowing you to focus on building awesome Clojure apps, not dicking around with implementing shell invocation, or Java compilation, or deployment via scp, or whatever “simple” build task you need today that’s been in Maven’s quiver for 5 years.
As if that weren’t enough, Sonatype has its Polyglot Maven project, where they are working on making it possible to drive Maven builds from your favorite language, be it Clojure, Ruby, Groovy, or Scala. For now, I stick to using XML POM files (they’re incredibly well-supported by tons of JVM-land tools – code completion on dependency version numbers FTW); while I love s-expressions, I’m too happy to trade off a pinch of syntactic elegance in exchange for tons more capability.
OK, enough blather. Demo-time!
With that said, let’s see what building a Clojure app using Maven looks like. First, the demo, where I start with the simplest Maven POM for building Clojure projects, and add in a Maven plugin to wrap my application into an OS X .app bundle (also available in HD):
For reference purposes, here’s that simplest of all Maven POM files you can use for your own projects:
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd"> <modelVersion>4.0.0</modelVersion> <groupId>com.snowtide</groupId> <artifactId>easy-maven</artifactId> <packaging>jar</packaging> <version>1.0-SNAPSHOT</version> <name>Easy Clojure Maven setup</name> <dependencies> <dependency> <groupId>org.clojure</groupId> <artifactId>clojure</artifactId> <version>1.1.0</version> </dependency> <dependency> <groupId>org.clojure</groupId> <artifactId>clojure-contrib</artifactId> <version>1.1.0</version> </dependency> </dependencies> <build> <plugins> <plugin> <groupId>com.theoryinpractise</groupId> <artifactId>clojure-maven-plugin</artifactId> <version>1.3.2</version> <executions> <execution> <id>compile-clojure</id> <phase>compile</phase> <goals> <goal>compile</goal> </goals> </execution> </executions> </plugin> </plugins> </build> <repositories> <repository> <id>clojure</id> <url>http://build.clojure.org/releases</url> </repository> </repositories> </project>
If you’re going to use Maven for your Clojure builds, here’s some links:
- Please make sure you check out the documentation on clojure-maven-plugin, which is where all of the Clojure-specific goals come from.
- You’ll do yourself a world of good by keeping the Maven books ready at hand (not the old one published years ago, BTW, the newer ones available online or through lulu). Yup, there’s a lot of material there. No, you don’t need to know it all to become super-productive with Maven.