Wednesday, March 24, 2010

Setting up a Clojure environment for Cygwin and Emacs, on Windows

I had to struggle a bit to come up with a satisfying Clojure environment on my Windows machine, so I thought it would helpful to try summarizing how I did it, while it's still fresh in my memory. I'll be covering two independent but related tasks: setting it up for Cygwin, then for Emacs (using SLIME).

Update: A reader suggested using freshly built jars from build.clojure.org, a very good idea, also meaning that more or less half of this post is not so useful anymore..

Update 2: Although I first describe setting up Clojure for Cygwin, the Emacs version I am referring to in the second part is actually the MinGW-compiled one, not the Cygwin one (see comments for more about this).

Cygwin Setup

My first experiment was with the precompiled jar files available on the Clojure Google Code page. It worked very well, but then I needed some additional string functions that could only be found in the 1.2 master branch of clojure-contrib at the time this was written, so I had to compile from source. For this you need a couple of things: first the JDK (I'm pretty sure the JRE alone wouldn't be enough), git (that you can install through the Cygwin Package Manager), Apache Ant (I used version 1.8.0) and Apache Maven (I used version 2.2.1). Once all that is installed and properly configured (it helps to have them all available on your PATH as well), you can download a copy of the Clojure source:

$ git clone git://github.com/richhickey/clojure.git


this command will actually create a "clojure" source directory right where you execute it, so you can "cd" to it, and then simply do:

$ ant


to compile. If everything goes all right, you should see BUILD SUCCESSFUL near the end, and then the Clojure jar file is ready to use. Next we build the clojure-contrib library, by first downloading it:

$ git clone git://github.com/richhickey/clojure-contrib.git


and then build it, with Maven this time, after having "cd"ed in the "clojure-contrib" sub-directory just created:

$ mvn package


..although for me, at the time of writing, this fails, with some testing error! If this is the case for you too, the trick is to skip the testing phase, by using instead:

$ mvn -Dmaven.test.skip=true install


You can now collect the two newly created jar files (clojure-1.X___.jar and clojure-contrib.1.X___.jar) and copy them in one unique folder, which will be handier for the remaining steps: we will refer to this location as <clojure_path> from now on. For convenience, I added to this lot the JLine jar file, that adds useful features to the Clojure REPL, like history navigation (using up/down arrows). The next step is to create a Bash file to startup your Clojure programs. Following the convention, create a file named clj, place it in the <clojure_path>, and edit it so that it contains, for instance:

CLOJURE_PATH="<clojure_path>" # e.g. c:/whatever/dir
CLASSPATH="$CLOJURE_PATH/clojure-1.2.0-master-SNAPSHOT.jar"
CLASSPATH="$CLASSPATH;$CLOJURE_PATH/clojure-contrib-1.2.0-SNAPSHOT.jar"
CLASSPATH="$CLASSPATH;$CLOJURE_PATH/jline-0.9.94.jar"
# ..and any other needed jar file..
java -cp $CLASSPATH jline.ConsoleRunner clojure.main "$@"


Please note that in this hybrid setup (Cygwin Bash, using Windows Java) the double quote and semicolon syntax must be carefully respected. Once this file is available on your PATH, you should be able to start a Clojure REPL by simply calling it:

$ clj


or execute a Clojure script:

$ clj your_script.clj [arg1 arg2..]

Emacs Setup

With a little more fiddling around, I was able to set up a Clojure environment for Emacs 23 on Windows as well (the MinGW-compiled version of Emacs, not the Cygwin-based one). Since the SLIME environment can download and install a Clojure environment all by itself, not much should remain to be said. However, I wanted it to use the latest binaries I had just compiled (not the 1.1 ones that were the default at the time I wrote this) and that is what I am going to describe here. It is very easy!

The first step is to install the very fine ELPA package manager for Emacs. Then invoke it using:

M-x package-list-packages


and put an "i" next to those four packages: clojure-mode, slime, slime-repl and swank-clojure. Then press "x" to download and install them all. Once done, you can summon SLIME:

M-x slime


and answer "y" when it asks you about installing a missing Clojure environment (even if you did build and install a fresh one already, like me, previously). Once it's installed, if you invoke SLIME again, it should launch a default 1.1 REPL. But if, like me, you are interested in running it with your own compiled jar files, you must do two things. The first is to locate the swank-clojure-1.X.X.jar file that the SLIME/Swank-Clojure setup has produced (for me it was located in c:\.swank-clojure), and copy it to your <clojure_path> (that is, the unique location where all the Clojure jar files you want to use should be found). Once this is done, the only thing that remains is to instruct SLIME and Swank-Clojure about this change, by setting a single variable in your .emacs file, like this:

(setq swank-clojure-classpath
(list "<clojure_path>/clojure-1.X.X-master-SNAPSHOT.jar" ; e.g. c:/whatever/dir
"<clojure_path>/swank-clojure-1.X.X.jar"
"<clojure_path>/clojure-contrib-1.X.X-SNAPSHOT.jar"
"<clojure_path>/jline-0.9.X.jar"))


and the next time you start Emacs, M-x slime should yield a Clojure REPL using your own compiled jar files, hopefully.

7 comments:

  1. Well, this doesn't work. Since cygwin doesn't have its own JDK, you have to use windows version. And windows version wants paths to start with c: not /cygdrive/c. I solved these problems by hacking on swank-clojure code a bit, but I wonder how you went around these issues if you do not even mention them in your post.

    ReplyDelete
  2. It works; please take some time to verify and test before posting. First the article states very clearly that this is about a "hybrid setup" (Cygwin Bash, using Windows Java). Second, in the clj script, I use a non-Cygwin path syntax for the <CLOJURE_PATH> variable, e.g. c:/whatever/dir (note the use of slashes, not backslashes). And third, for the swank-clojure-classpath Emacs variable, I use exactly the same syntax, which works very well on my MS Emacs 23 setup. No cygdrive reference, and no swank-clojure hacking required!

    ReplyDelete
  3. Do you know about build.clojure.org? You can get the latest version of clojure and contrib jars there instead of building your own. Just FYI.

    ReplyDelete
  4. Thanks Phil, I wasn't aware of it.. I'll update my post accordingly.

    ReplyDelete
  5. I actually did verify. At this moment, I am working on the swank-clojure code to make it work under cygwin. The main problem that cannot be avoided by setting your own classpath is the path to the socket file SLIME uses to connect to swank and the way swank-clojure handles classpath. Without modifications it just doesn't work.

    ReplyDelete
  6. You can take a look at my mods at
    http://github.com/MadWombat/swank-clojure

    ReplyDelete
  7. Hi, I've just posted a small tip for calling java from Cygwin, thought it'll would complement your post nicely:

    http://whollyweirdwyrd.blogspot.com/2010/04/cygwin-tip-1.html

    ReplyDelete