Skip to content

Instantly share code, notes, and snippets.

@abuxton
Forked from rakhmad/clojure.md
Created August 18, 2014 09:15
Show Gist options
  • Save abuxton/94d34b59faee8523cbe9 to your computer and use it in GitHub Desktop.
Save abuxton/94d34b59faee8523cbe9 to your computer and use it in GitHub Desktop.

Setting Up Clojure on OS X

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.

Step 1: Getting Clojure (1.3)

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

Step 2: (Mis-) Understanding Clojure.Contrib

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.

Step 3: Leiningen and Clojure Projects

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).

Installing 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.

Your First Project

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…

Step 4: A Development Environment

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).

Dismissing Emacs + Slime and Vim + VimClosure

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:

Emacs + Slime

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.

Vim + VimClojure

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…

Note: References made to installing nailgun you can ignore and just use Homebrew: brew install nailgun.

A Better Solution: Sublime Text 2

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.

Getting a Sublime REPL…

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).

SublimeREPL Supports Leiningen!

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.

Step 5: Using Local Libraries

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).

Understanding Maven Repositories (basic)

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

Installing Libraries

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!

An Example

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.

Downloading

First, let's download and it:

$ git clone git://github.com/technomancy/server-socket

Compile a JAR

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

Installing the 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.

Updating the Project File

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

Loading It Up!

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.

Conclusion

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.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment