2010-06-08

Building Clojure projects with Leiningen

When I first started learning Clojure, I had no idea the ecosystem it was situated in. C and C++ is situated in an ecosystem where there's make for managing the building of an application, and GCC for compiling the code. You can use a plain text editor to actually write the program if you like, there's a debugger GDB, and version control can be with CVS, Git, or whatever else. emacs is a plain text editor that also has the option of pulling together all these separate parts together to work as one integrated development environment.

Of course, nowadays people seem to like the whole IDE concept so much it's probably the most popular way to program (Apple Xcode, Eclipse, NetBeans, etc). For Clojure, you can use some of those IDEs too, eg, using NetBeans with the Enclojure plug-in.

If you like the "bag of separate tools" way (the "unix way") of programming, as I do and as I described for C at the beginning, then you'll like Leiningen - I think of it as a much better make, but for Clojure. It's documentation is sparse right now, so the following may help you.


Installation is easy. Just see the Installation section of the README.md file. I have Leiningen 1.1.0.

Let's say you've cd ~. Then lein new hello will create a new project space for you in ~/hello, so cd ~/hello to go into it.

You'll notice in ~/hello Leiningen already created some templates for you. You'll modify project.clj to tell Leiningen what your project's dependencies are for building and while developing. Your source code should go into src/hello.

Let's write a classic "Hello World!" program using emacs (or use your own favourite plain text editor, pico or whatever).

Do emacs src/hello/core.clj.  Right now, it should only have one line:

(ns hello.core)

That declares the namespace. Modify it so that it says:

(ns hello.core
    (:gen-class))
(defn -main [& args]
    (println "Hello World! " (apply str args)))

Save, and exit emacs. The function -main will be the "main" function to enter this namespace with by Java and Clojure, later when the application is built and ran from command line. Notice the args variable: that will contain a sequence of arguments supplied from the command line (the function here just concatenates and prints the arguments out after "Hello World!").

Now do emacs project.clj, which should currently have the following:

(defproject hello "1.0.0-SNAPSHOT"
  :description "FIXME: write"
  :dependencies [[org.clojure/clojure "1.1.0"]
                 [org.clojure/clojure-contrib "1.1.0"]])

Modify it so it says:

(defproject hello "1.0.0-SNAPSHOT"
  :description "FIXME: write"
  :dependencies [[org.clojure/clojure "1.1.0"]
                 [org.clojure/clojure-contrib "1.1.0"]]
  :main hello.core)

The :main will tell Java and Clojure which namespace to "enter" the program with (and within the hello.core, the -main function will be the first function called).

Now do lein uberjar

There will now be within the ~/hello directory a hello.jar file, which is the compiled result of your hello package, and a hello-standalone.jar.

This standalone file has all the Clojure dependencies — everything — packed into one file for easy distribution and deployment. Just send that standalone file on to someone with Java installed and they can run your application!

So how to run that standalone application then?

java -jar hello-standalone.jar Argument1 Arg2 etc

If you ran the program exactly as above, then you should get this output:

Hello World!  Argument1Arg2etc

Success!

You may want to learn more about command line arguments now. Or more about namespaces.

This tutorial is based on another by Zef Hemel, but his was written back in November 2009. Some things has changed since then, but his tutorial is perhaps a tad bit more detailed. This one here is more narrowly focused on just getting you up and building applications that can be later distributed.

4 comments:

Mr Speaker said...

Great tutorial, thanks!

How work in "dev mode" - without having to build and run jars on every change?

blogger said...

During development, I use emacs with swank, then I can test changes in the Clojure repl without having to build java jars with every change.

The easy way to get a Clojure repl running is to use the command lein repl from within your lein project folder. Then you can use (load-file "path/to/codefile.clj") in the repl to load the codefile.clj.

So using the example in the post above, you would (load-file "src/hello/core.clj") in the lein repl, then you can run the -main function with (hello.core/-main "Arg1" "Arg2").


Alternatively, if you use emacs, like I do, then you can get a more full-featured Clojure repl like this. You'll need to install a few packages for emacs first, including: slime, slime-repl, and swank-clojure (I suggest you use emacs' ELPA package system to install those).

Then you can run swank with the command lein swank from within your project folder. Lein will start a swank server from your project folder.

Then from within emacs, connect to the swank server with the command M-x slime-connect (Just hit return when prompted. There'll be a few prompts).

Then you'll have a running Clojure repl from within emacs to do development in. You can again use that (load-file ...) command as above, or you can ask emacs to compile files for you and run individual functions you want from the Clojure repl.

I wrote up some notes (not really a tutorial) for doing that in a previous post.

Full instructions for doing all that in emacs would be kinda long, so if you want me to explain, let me know and I'll just write up a new blog post for it.

Unknown said...

Worked like a charm!

Unknown said...

Worked like a charm!