Friday, January 15, 2010

Manual Installation (not using ELPA) of swank-clojure

There appears to be a lot of discussion on getting slime and emacs integrated with Clojure similar to how it is with Common Lisp. For most setups, Technomancy has made it easy to quickly setup the IDE by installing Swank Clojure via ELPA in emacs. Those who don't like using ELPA or need to hack on the sources, need to install the software manually. I present my manual installation experiences and I hope it may be useful to others.

Obtaining Software


I relied on my distribution's package manager to install emacs and slime (as well as git, java, and everything else not listed) but the following packages,

clojure
clojure-contrib
leiningen
swank-clojure
clojure-mode

are rapidly developed and at the moment are not best handled by my package manager so I installed them from source. To keep things organized, I downloaded the sources in their own directory.

mkdir ~/clj
cd ~/clj
git clone git://github.com/richhickey/clojure.git
git clone git://github.com/richhickey/clojure-contrib.git
git clone git://github.com/technomancy/leiningen.git
git clone git://github.com/technomancy/swank-clojure.git
git clone git://github.com/jochu/clojure-mode.git

I was now free to hack, but I needed to build them before use.

Building Software


Swank Clojure depends on Leiningen and Leiningen depends on Clojure so I needed to build that first.

I built clojure as specified in the readme.

cd ~/clj/clojure
ant

I setup an installation directory for Clojure with a minimal folder structure. I don't know what recommended layout is but I copied my distribution's version of clojure.

cd ~/clj
mkdir -p runtime runtime/bin runtime/classes runtime/lib

I then populated the folders. In runtime/bin, I had a simple repl.sh script

#!/bin/bash
java -cp ~/clj/runtime/lib/clojure.jar clojure.main

and in runtime/lib I symlinked all the jars. At the time, the only clojure.jar was built so I linked it.

cd ~/clj/runtime/lib
ln -s ~/clj/clojure/clojure.jar

I tested clojure by by running the repl.sh script.

Next I built clojure-contrib as specified in the README.

cd ~/clj/clojure-contrib
ant -Dclojure.jar=~/clj/runtime/lib/clojure.jar
ln -s ~/clj/clojure-contrib/clojure-contrib.jar ~/clj/runtime/lib

Next was Leiningen, which depends on itself so I needed to bootstrap it. The stable build script installs a version in the ~/.m2 folder. I put the script in my PATH and ran it.

cd ~/bin # this folder is in my path
wget http://github.com/technomancy/leiningen/raw/stable/bin/lein
chmod +x lein
mv lein lein-stable
lein-stable self-install

Next I built my checkouted Leiningen, added the checkouted lein into my path, and added the jar to ~/clj/runtime/lib

cd ~/clj/leiningen
lein-stable deps
ln -s ~/clj/leiningen/bin/lein ~/bin/lein
lein jar
ln -s ~/clj/leiningen/leiningen.jar ~/clj/runtime/lib

Next I built swank-clojure and linked the jar

cd ~/clj/swank-clojure
lein jar
ln -s ~/clj/swank-clojure/swank-clojure.jar ~/clj/runtime/lib

Next I needed to configure my .emacs file to swank-clojure and clojure-mode with some slight modifications in order to work with mismatched versions of clojure and clojure-contrib with swank-clojure

Reading ~/clj/swank-clojure/swank-clojure.el allowed me to understand all the configuration parameters for swank-clojure. I highly recommend reading that file if you want to tweak anything in swank. It's well written and has good documentation.

;; in the .emacs file, clojure configuration
;; to run slime, M-- M-x slime then type clojure

;;tells emacs where to find clojure-mode.el
(add-to-list 'load-path "~/clj/clojure-mode")
(require 'clojure-mode)

(setq swank-clojure-jar-home "~/clj/runtime/lib")
;; need to override default deps so self-install is not evoked
;; the URLs are honestly arbitrary, I essentially just removed
;; the version info so that the filenames match the filenames
;; of the jars I built
(setq swank-clojure-deps
      (list (concat "http://repo.technomancy.us/"
                    "swank-clojure.jar")
            (concat "http://build.clojure.org/snapshots/org/"
                    "clojure/clojure/1.1.0-master-SNAPSHOT/"
                    "clojure.jar")
            (concat "http://build.clojure.org/snapshots/org/"
                    "clojure/clojure-contrib/1.1.0-master-SNAPSHOT/"
                    "clojure-contrib.jar")))
(add-to-list 'load-path "~/clj/swank-clojure")
(require 'swank-clojure)
;; needed for overriding default method for invoking slime
(ad-activate 'slime-read-interactive-args)

That was it. To run slime, I just typed in emacs, "M-- M-x slime" then "clojure". I use "M--" so I can still run SBCL if I need to.

Hopefully this information may be useful to the community.