I spent a lot of time trying to find a pretty optimal (for me) setup for Clojure… at the same time I was trying to dive in and learn it. This is never optimal; you shouldn't be fighting the environment while trying to learn something.
I feel like I went through a lot of pain searching Google, StackOverflow, blogs, and other sites for random tidbits of information and instructions.
This is a comprehensive "what I learned and what I ended up doing" that will hopefully be of use to others and act as a journal for myself if I ever have to do it again. I want to be very step-by-step and explain what's happening (and why) at each step.
I was already familiar with (and had) Homebrew (http://mxcl.github.com/homebrew/). If you don't already have Homebrew installed, I highly recommend getting it. I won't cover that hear as it's not that difficult, but I also don't want to be responsible for you accidentally blowing away your /usr/local
path… ;-)
But, assuming you have Homebrew installed, let's install the latest version of Clojure:
$ brew install clojure
When starting to learn Clojure, many people are like myself and want to dive into a personal project immediately. For myself, I have several common apps I like to make with any new language to get a sense of how it works. I chose a simple telnet-based chat server.
I performed a quick Google search for "clojure sockets" and "clojure streams" and was immediately presented with several pages where various libraries (in clojure.contrib) could help me out. I then spent the next several hours trying to figure out how to get them to work.
The problem is that - with Clojure 1.3 - the "contrib" library was removed in favor of breaking the libraries up and either putting them into their own library or embedding them into Clojure's core. This is a good page to use as a reference for what's happened to various contrib libraries you might come across online:
http://dev.clojure.org/display/design/Where+Did+Clojure.Contrib+Go
Just know that if you are reading a tutorial on Clojure that makes use of a clojure-contrib
library, it's out of date and you might need to look at the above link to see what happened to the library in question.
The next step was learning how to setup a Clojure project. Almost all Clojure tutorials and examples I came across would mention a project.clj
file, but then fail to give any details. I wasted a ton of time learning about the JVM's CLASSPATH (note: I'm new to the JVM) and trying to "make it work" unsuccessfully. As it turned out, there's a wonderful tool out there created by Phil Hagelberg that helps with this called Leiningen (https://github.com/technomancy/leiningen).
Homebrew again comes to the rescue and can install it for you:
$ brew install leiningen
Once installed, Leiningen solves many important problems for you, mostly dealing with Java's CLASSPATH, project setup, dependencies, and building.
Once Leiningen is installed, you can use it to create a new Clojure project that you can begin to toy with.
$ lein new myproj
This will create a new folder myproj/
off the current directory, along with a simple skelton (including a .gitignore
file, how helpful):
+
| project.clj
| README
+ src/
| + myproj/
| | | core.clj
+ test/
| + myproj/
| | + test
| | | core.clj
Now, if take a quick look at project.clj
we can see a basic setup for our first project:
(defproject myproj "1.0.0-SNAPSHOT"
:description "FIXME: write description"
:dependencies [[org.clojure/clojure "1.3.0"]])
For right now, the most important part of this file is the :dependencies
section. This is a list of what myproj
requires in order to load, compile, and run.
If you remember the hint from earlier, the JVM has a CLASSPATH environment variable that is used find required libraries. What Leiningen does for you is take your list of dependencies and install them to a known location for your project. This is done with the deps
command:
$ lein deps
Copying 1 file to ./myproj/lib
If you take a look there is now a lib/
folder in your project directory and it contains the single jar dependency for Clojure that was specified in your project.clj
file.
At this point, we have everything we need to start playing around and making interesting things happen. We can use Leiningen to start Clojure now from within our project folder and have access to all of our dependencies and project source files.
$ lein repl
REPL started; server listening on localhost port 17970
user=>
For now we're going to move onto the next step, but we'll be coming back to Leiningen later…
This is where - as with any programming language - the community diverges incredible into a whole plethora of recommendations. And, as with any language that's remotely based on Lisp, Emacs + Slime will be the #1 recommendation.
I've used Emacs for years for Common Lisp development with Slime and I love it. And I've also used Vim for lots of editing and it has lots of wonderful features as well. I say that because my recommendation will not use either, and I wanted you to know that I do use them and love them. So my recommendation to use something else is based on the fact that I put serious effort into getting either to work, failed miserably, and don't believe anyone should have to go through that kind of hell (that - and frankly - Emacs/Vim isn't for everyone).
In case you are interested in plowing your own path at this point and making Emacs work for you with Slime, or VimClosure with Vim, here's a couple links/hints to help you get going:
First, you can download a Clojure mode for emacs here:
https://github.com/jochu/clojure-mode
Now, the Swank server for Clojure is old. This means you're going to have to get an old version of Slime to work with.
This can be done many ways, and if you know Emacs then this shouldn't be a serious problem for you. Simply put, put a current version of Slime in .emacs.d/slime-current
and the old version for Clojure in .emacs.d/slime-clojure
, then make two functions, based on which one you want to use:
;; load slime for common lisp
(defun slime-common-lisp ()
(interactive)
(add-to-list 'load-path "~/.emacs.d/slime-current")
(require 'slime)
(slime-setup '(slime-fancy))
(slime))
;; load slime for clojure
(defun slime-clojure ()
(interactive)
(add-to-list 'load-path "~/.emacs.d/slime-clojure")
(require 'slime)
(slime-setup '())
(slime-connect "localhost" 4005))
Note: I cannot claim credit for this… This was put together after a very late night of scouring the internet and coming across several posts on StackOverflow which lead me to this solution. I wish I had links to post, but I've long-since closed the pages. If you have them, send them my way and I'll update this post.
Next, you'll need to update your project.clj
file and add a new dependency (as a plugin) for Swank. This is easy enough to do, simply add the following line to the file:
:plugins [[lein-swank "1.4.4"]]
Once this has been done, you can then use Leiningen (yep!) to start up a Swank server for you:
$ lein swank
Connection opened on localhost port 4005.
You should now be able to launch Emacs, M-x clojure-mode
, and connect to the Swank server with M-x slime-clojure
.
I'm not going to spend much time here. Sorry. I know Vim well enough to use it and to make a few Vim scripts, but not well enough to follow a lot of the pages I found discussing screens, pathogen, etc.
Needless to say I tried, but at 2am in the morning, my brain wasn't functioning well enough to comprehend everything I was reading. Instead, here are several links which might help you if this is a path you want to go down…
- http://www.vim.org/scripts/script.php?script_id=2501
- http://blog.darevay.com/2010/10/how-i-tamed-vimclojure/
- http://naleid.com/blog/2011/12/19/getting-a-clojure-repl-in-vim-with-vimclojure-nailgun-and-leiningen/
Note: References made to installing nailgun
you can ignore and just use Homebrew: brew install nailgun
.
Before you read this section, you should know up-front that this isn't a "free" path: Sublime Text 2 (http://www.sublimetext.com/2) is awesome, but it's also a commercial product ($59 US). There is a free trial, so go ahead and give it whirl; I'm quite sure you'll love it as much as I do.
Once you have Sublime installed, the next step is to get a Clojure REPL going inside it (much like in Emacs, but just not quite as powerful). To do that, we need to install a wonderful plugin for Sublime called SublimeREPL (https://github.com/wuub/SublimeREPL).
$ cd "$HOME/Library/Application Support/Sublime Text 2/Packages/"
$ git clone git://github.com/wuub/SublimeREP
That's all there is to do! Once installed, if you were to startup Sublime, you can cruise over to Tools -> SublimeREPL -> Clojure -> …
and start one up (also notice the support for REPLs in plenty of other languages).
What's best about SublimeREPL is that - out of the box - it already has support for Leiningen. All you need to do is open your project.clj
file in Sublime, and (with that file's tab active) start a Clojure REPL (not the telnet version of the REPL).
Once started, you can now run code from within the Sublime REPL, you'll have access to all your dependency libraries, and be able to load your own project files as well.
user=> (use 'myproj.core :reload-all)
nil
Hint: Use ctrl+p
and ctrl+n
to cycle through the REPL history.
Leiningen uses a Java program called Maven to get at libraries. I'm not even close to a beginner at using/understanding Maven, but you should generally be aware of it and where your jars are being copied from (via lein deps
).
In your home directory is a .m2/
folder. Inside that is a repository
folder. At this point, if you ls
you'll see a lot of directories.
One in particular that should stand out is the org
folder, inside which is the clojure
folder, inside that is another clojure
folder and, finally, inside that, is a list of one or more version folders. And, if you look inside the 1.3.0
directory, you'll see the jar for clojure-1.3.0.
Now, if you reference back to your project.clj
file, in the dependencies section, do you remember this?
:dependencies [[org.clojure/clojure "1.3.0"]]
So, now you can see how that dependency description turned into a jar file that was copied into the lib/
folder of your project:
[org.clojure/clojure "1.3.0"] ->
~/.m2/repository/org/clojure/clojure/1.3.0/clojure-1.3.0.jar
Now, let's say you find a nice Clojure library somewhere in GitHub that you would like to use. How do you install it and use it in your own projects? Again, Leiningen is here to help us out. There is a wonderful plugin for Leiningen called "lein-localrepo":
https://github.com/kumarshantanu/lein-localrepo
Check out the README.md file to see how to install it for different versions of Leiningen. I'm going to assume that you are using a version < 2.0 for the rest of this tutorial (use lein version
to see which version you have installed).
$ lein plugin install lein-localrepo "0.3"
Once installed, you can then use Leiningen and the localrepo plugin to add Clojure libraries others have written to your Maven repositories and reference them in your project.clj
file!
Phil Hagelberg (creator of Leiningen) has a nice port of clojure.contrib's server-socket library for Clojure 1.3 that we'll download, compile, install, and load into our project.
First, let's download and it:
$ git clone git://github.com/technomancy/server-socket
Next, we need to compile it. This uses Leiningen since server-socket is a Leiningen-based project. If it wasn't, you would use a different method to build a jar.
$ lein jar
Created ./server-socket-1.0.0.jar
Now, let's decide where we're going to install it to. We can install it where-ever we want, but sometimes Leiningen has a suggestion. Let's ask where Leiningen and the localrepo plugin thinks it should go:
$ lein localrepo coords server-socket-1.0.0.jar
server-socket-1.0.0.jar server-socket/server-socket 1.0.0
The output says that - in the ~/.m2/repository
folder - it thinks it should go under server-socket/server-socket
with version "1.0.0". So, let's follow the suggestion:
$ lein localrepo install server-socket-1.0.0.jar server-socket/server-socket 1.0.0
Let's verify that it went where we expect it to go:
$ ls ~/.m2/repository/server-socket/server-socket/1.0.0
server-socket-1.0.0.jar
Yep! It's been installed successfully and is ready for use.
It's important to note that we didn't have to install it to the recommended location. We could have installed it somewhere else. For example, we could have chosen local.repo/server-socket
instead. It's entirely up to us.
In order to have Leiningen install the library for our project to use, it will need to know about it. So, at this point we'll need to update the :dependencies
section of our project.clj
file:
:dependencies [[org.clojure/clojure "1.3.0"]
[server-socket/server-socket "1.0.0"]]
And, once saved, we can go to the project directory and update our installed dependencies for the project:
$ lein deps
Copying 2 files to /Users/jeff/Projects/myproj/lib
Finally, let's head back into Sublime, to our project.clj
file, and relaunch the Sublime REPL for Clojure. Once it's up and running, let's see if we can use it…
user=> (use 'server.socket)
nil
Yep!
Note: We knew it was server.socket
and not server-socket
because in the GitHub repository for server-socket the class was located at src/server/socket.clj
and socket.clj
had the namespace server.socket
.
Being new to Clojure, the above took me quite a while to figure out (a couple late nights), and I'm sure there's still quite a lot I'm missing or don't fully grok (especially with respect to Maven). All the tutorials and guides I came across all seemed to assume an understanding of Java and/or other aspects of what was happening. Here's hoping that this guide can help others so that they don't have to spend forever just trying to get a simple Clojure project up and running and give this language (and Lisp) the chance it deserves.