This article describes the Leiningen tool (version 1.x) for building of projects, written in Clojure.5
Leiningen is a tool for building of code, written in Clojure. Leiningen is much simpler comparing with Maven and allows to define project's configuration using Clojure1. Leiningen uses external tools and libraries to resolve dependencies and build a code, so it's pretty small. This tool is getting more popularity between Clojure developers — it's extensible by using additional modules (plugins), such as plugin for compilation of Java code, and many others.
Out of box Leiningen implements basic tasks — compilation of code, testing, creation of package, installation, etc. Besides this, it also provides basic support for work with Maven, so you can use packages, built by this tool in other projects.
Leiningen's installation procedures for Unix-like OSes and for MS Windows are slightly
different. Installation on Unix is quite easy — you just need to download lein script,
make it executable, copy to directory, listed in PATH
, and execute lein self-install
command. During execution of this command, Leiningen will download and install all
packages, that are needed to its work.
To install Leiningen on MS Windows you need to download lein-win32.zip file from project's
page. This file contains all necessary programs, so you can unzip it into any directory,
add this directory into search path, perform lein self-install
command, and start to work
with Leiningen.
Leiningen uses fixed structure of project — in the root directory of the project you need
to have the project.clj
file, that contains project's definition. The only necessary
component of the definition is defproject
— Clojure's macro, that is expanded into set of
build instructions. project.clj
can also include other code, written in Clojure, that
will executed during build process.
Project's source code should be stored in src
directory, tests — in test
directory, and
additional resources, used by project — in resources
directory. The lib
directory is
used to store libraries, used by project — they are copied there with the lein deps
command. List of libraries is calculated using information about dependencies, declared
in project. If you want to use library, that isn't stored in one of the Maven's
repositories, then you can just copy this library into lib
directory, and it will
available to your project.
But names of directories aren't hard-coded — you can use defproject
's options
to change their values:
:source-path
src
);:compile-path
classes/
);:resources-path
resources/
);:test-path
test/
);:library-path
lib/
).You can also add additional information to project's definition — description (the
:description
option) and link to project's home page (the :url
option).
The fastest way to create a new project is to use lein new
command, that accepts one
required argument — name of the project. This command will create a new directory with
name of the project, and will create inside it the project.clj
file with declaration of
the project (including dependencies on Clojure and clojure-contrib
), the README
file with
template of project's description, and two directories —
src
and test
for source code &
tests. Now you can start to work with you project.
Let look to simple project specified in project.clj
with following code (full code of this
project you can find at github):
(defproject test-project "1.0-SNAPSHOT" :description "A test project." :url "http://my-cool-project.com" :dependencies [[org.clojure/clojure "1.1.0"] [org.clojure/clojure-contrib "1.1.0"]] :dev-dependencies [ [swank-clojure "1.2.0"] ] )
We define a project test-project
with dependencies on Clojure and clojure-contrib
libraries, and also have additional dependency on library, that we'll use during
development —
swank-clojure
.
In the src
directory there is only one file —
simple.clj
, that declares namespace simple
with following code inside:
(ns simple) (defn hello ([] "Hello world!") ([name] (str "Hello " name "!")))
In the test
directory we have file simple_test.clj
, that contains test for simple
. We're
using standard library clojure.test
to implement test. Test's source code looks following
way:
(ns simple-test (:use clojure.test) (:use simple)) (deftest simple-test (is (= (hello) "Hello world!")) (is (= (hello "test") "Hello test!")))
This is complete project, and we could execute any Leiningen's command for it.
One of important parts of defproject
is declaration of dependencies on external libraries.
For code, written in Clojure, main dependency is Clojure itself, as this shown in example
above.
There are different types of dependencies and different project options for them:
:dependencies
option:dev-dependencies
optionswank-clojure
, Leiningen's plugins, etc.Besides this, exists native-deps plugin, that implements support for dependencies on platform-dependent libraries (native libraries). Here is example of use of this plugin.
Each of these options is a vector, where each element is another vector, holding description of concrete library. This description consists from three elements (you already had seen these descriptions in project's example):
org.clojure/clojure
;"1.1.0"
or "1.2.0-master-SNAPSHOT"
, for example.
But you can also list several "supported" versions, if you specify version as vector
with values, separated by comma, "[1.1,1.2-SNAPSHOT]"
, for example;:exclusions
option.
Here is example of excluding of some not necessary dependencies for log4j
library:[log4j "1.2.15" :exclusions [javax.mail/mail javax.jms/jms com.sun.jdmk/jmxtools com.sun.jmx/jmxri]]
By default Leiningen uses three repository:
Besides this, user can specify additional repositories with :repositories
option. This
option take one parameter — map with names and URLs of repositories. For example, we can
add repository of Apache project with following code:
(defproject test2 "1.0.0-SNAPSHOT" :dependencies [....] :repositories {"apache-releases" "http://repository.apache.org/content/repositories/releases/"} )
Typical workflow when you use Leiningen looks following way:
lein new
), define dependencies on external libraries and download
them with lein deps
command (you need to run it after each change of dependencies);lein compile
, lein test
, and may be using
lein repl
, lein swank
or lein nailgun
(depending on your personal preferences) for
interactive development;lein install
command, or you can upload it to
Clojars (with scp
, as suggested in documentation, or by using the lein-clojars
plugin);lein jar
command (only your code, without dependencies), or with lein uberjar
, with all
dependencies included into package — it's much easier to distribute such packages to
end users.This process is pretty simple and you repeat it until your code is complete :-)
List of Leiningen's commands isn't fixed — plugins could add new commands to it. In
basic configuration, Leiningen implements following commands, that could be run as lein
command [options]
:
help [command]
help
, then description of command will shown (except repl
)new project_name [options]
deps
lib/
directory. This
command should executed after each change in dependencies!;compile
classes/
directory. User can control which namespaces should be
compiled — you can use :namespaces
option to specify a list of namespaces to compile;test [list_of_namespace]
jar
uberjar
java -jar ...
then entry point will namespace, specified in :main
option, specified
defproject
;pom
pom.xml
file, that contains description of project. This file is needed
if you plan to use your package in another project;install
clean
lib/
directory);repl
lib/
directory, and also directories src/
and classes/
. During start lein
2 automatically
detects presence of jline library, and uses it, so you'll have command history, etc.Additional commands are implemented by plugins, that are used to extend Leiningen's functionality. There are many popular plugins for Leiningen, and you can find short description of many of them in following blog posting. For example, this are plugins for running of Swank and Nailgun servers, that are implementing interactive work from Emacs or Vim. If you run these servers, then they are using all necessary dependencies, so you will work in the same environment, as your program.
To use Swank server you need to add dependency on swank-clojure3 in :dev-dependencies
option4, and after this you could use lein swank
command. After execution of this
command you'll get Swank server, running on port 4005 and you can connect to it with
Emacs' slime-connect
command. And if you prefer to use Vim editor, then you need to add
dependency on lein-nailgun plugin (more about work with Nailgun you can read on
vimclojure's site).
Leiningen is extensible — if necessary, you can add your own commands. To do this you
need to create a project, in which exists leiningen.command_name
namespace, containing
implementation of your command as a function with name command_name
. This function
receives project's object as an argument. More detailed information on writing plugins
you can find in following blog post. One of example of plugins for Leiningen is the
lein-swank
plugin, that implements support for Swank server — you can find it in
Leiningen's repository with source code.
There are several plugins for Leiningen in Clojars repository. These plugins implement
different functionality — automatic uploading of code into Clojars repository, building
of Java source code, etc. Names of these plugins usually starting with lein-
, that you
can use in search. To use these plugins in your project, you need to add them into
development dependencies (the :dev-dependencies
option).
I hope, that this article helps you in your work with Leiningen. If you have questions you can write me e-mail or leave a comment on site — I'll try to answer on all of them.
1. I should also mention the Polyglot Maven project, that should allow to describe Maven's configurations using different languages — Clojure, Scala, Groovy, etc.
2. In contrast to other commands, repl
is implemented directly in lein
, not written in
Clojure.
3. example of swank-clojure
dependency you can see in project's example.
4. and don't forget to run lein deps
after adding this dependency!
5. there is also small document in Leiningen's distribution, that describes basic operations.
Last change: 05.03.2013 16:54