Clojure Leiningen Tutorial
Leiningen is a command line tool to automate things when working with Clojure. If you work with Clojure in real world projects, then Leiningen is necessary.
Leiningen home page is http://leiningen.org/
This tutorial is for people who have never done Java or Clojure before. I tell you why you need to use leiningen, how to use it, and many things you need to know in using it.
Why is Leiningen Needed?
Leiningen is basically necessary because:
- It is very tedious to build/run software in Java world. You need to constantly compile files, create directories, set class path, run, generate jar files, edit code, repeat. Leiningen automates this.
- Leiningen has a much enhanced Clojure command line interface (aka REPL). Emacs or other tools can connect to it. This lets you eval Clojure code in emacs, etc.
- Leiningen is very popular. Most Clojure libraries require or assume you have Leiningen installed.
What Does Leiningen Do?
Leiningen is a command-line tool that does many things. The most important are:
- Build project. (compile things by a config file. (the config file is named “project.clj”))
- Manage packages. Install/fetch/search packages with dependencies automatically.
- Run Clojure REPL with the libraries you need loaded for you.
- Package your Clojure project into one self-contained file. (a Java “uber” jar file.)
- Publish your lib to standard repositories. (Java world's “Maven Central” at http://search.maven.org/, or Clojure's Clojars at https://clojars.org/ )
Install Leiningen
- Download the lein script at https://raw.githubusercontent.com/technomancy/leiningen/stable/bin/lein (or on Windows lein.bat at https://raw.githubusercontent.com/technomancy/leiningen/stable/bin/lein.bat )
- Place it on your $PATH where your shell can find it (For example, at
~/bin
) - Set it to be executable (That is, run
chmod a+x ~/bin/lein
) - Run it in terminal (type
lein
) and it will download and self-install.
How to add to bash $PATH?
Here's a example of how to add lein to your path.
Suppose you have lein script at ~/bin/lein
.
Add the following to your bash profile ~/.bashrc
:
PATH=$PATH:$HOME/bin
After that, open a new terminal window or source ~/.bashrc
.
Where is Leiningen installed?
lein
is just a bash script. You can place it anywhere. I put it at ~/apps/lein/lein
.
After you run it, it'll download stuff at ~/.lein/
It'll basically just download this jar file leiningen-2.6.1-standalone.jar
. (The file size is 16M.)
Leiningen is basically a combination of the lein
shell script and Java. The shell script is a frontend. The meat is the jar file. It is written in Clojure, running on JVM (Java Virtual Machine).
What is a jar file?
Jar file is a archived file of Java. It is how Java software are distributed. Typically, you start a Java app by java name.jar
.
Jar file is a bunch of compiled Java class files of a directory, plus some extra info (such as which class file is the entry point.) (Java software is a set of compiled class files.)
When working with Clojure, you need to be familiar with Java tools and its package system, sooner or later. Bookmark the following to read later:
What is uber-jar?
“Uber jar” means jar file that contains all libraries a app needs. So, user just need this one single jar file to run the app. (as opposed to, needing to download other jar files and put them in class path.)
lein
can create uber jar file for your project.
What is Ant? What's Maven?
They are build tools in the Java world. (similar to unix make
).
See: What is Apache Ant, Apache Maven, What's the Difference?
Java world has a lib repository called Maven Central (or just Central) at http://search.maven.org/
Because Clojure runs on JVM (Java Virtual Machine), so Clojure files are also compiled into class files, and is also packaged into jar files.
lein
has features to help upload Clojure lib to Maven.
Leiningen Help
- Type
lein help
to get a list of commands. - Type
lein help command
to see help for that particular command. For example,lein help repl
$ lein help Leiningen is a tool for working with Clojure projects. Several tasks are available: change Rewrite project.clj by applying a function. check Check syntax and warn on reflection. classpath Print the classpath of the current project. clean Remove all files from project's target-path. compile Compile Clojure source into .class files. deploy Build and deploy jar to remote repository. deps Download all dependencies. do Higher-order task to perform other tasks in succession. gorilla help Display a list of tasks or help for a given task. install Install the current project to the local repository. jar Package up all the project's files into a jar file. javac Compile Java source files. new Generate project scaffolding based on a template. plugin DEPRECATED. Please use the :user profile instead. pom Write a pom.xml file to disk for Maven interoperability. release Perform :release-tasks. repl Start a repl session either with the current project or standalone. retest Run only the test namespaces which failed last time around. run Run a -main function with optional command-line arguments. search Search remote maven repositories for matching jars. show-profiles List all available profiles or display one if given an argument. test Run the project's tests. trampoline Run a task without nesting the project's JVM inside Leiningen's. uberjar Package up the project files and dependencies into a jar file. update-in Perform arbitrary transformations on your project map. upgrade Upgrade Leiningen to specified version or latest stable. vcs Interact with the version control system. version Print version for Leiningen and the current JVM. with-profile Apply the given task with the profile(s) specified. Run `lein help $TASK` for details. Global Options: -o Run a task offline. -U Run a task after forcing update of snapshots. -h, --help Print this help or help for a specific task. -v, --version Print Leiningen's version. See also: readme, faq, tutorial, news, sample, profiles, deploying, gpg, mixed-source, templates, and copying.
Most Useful Lein Commands
The most basic useful commands are:
lein repl
- Starts a server based Clojure REPL. You can use this instead of the standard Clojure REPL. (this allows you to have other tools such as emacs to connect to it. And also automate loading all dependent libraries of your project.)
lein new app name
- Creates a new empty project. That is, creates a directory structure named name at current dir . (dir structure is necessary, because compiled language need source, target, dependency list, etc.)
lein run
-
Run your Clojure app. By default, it runs the file
project_name/src/project_name/core.clj
First Lein Session: lein repl
First thing to try is to run lein repl
in terminal.
What is the difference between Clojure REPL and Leiningen REPL?
lein repl has many advantages:
- You can press ← to move cursor back and edit.
- You can press ↑ for history.
- Automatically compile, recompile, and load all your code and project's dependencies.
- You can type
javadoc java obj or class name
to view Java documentation. It will launch browser to the java doc page. For example,javadoc String
.
Leiningen: You Must Have a Project
Most Leiningen commands make sense only if you have a project.
What is a “project”? What does it mean exactly?
A project is just a directory, usually with some subdirectory that has conventional meaning. For example: source code directory src
, compiled file directory target
, dependencies (libs) directory, etc.
These are necessary because Clojure is a hosted language on JVM. Java is a compiled language. Compiled languages typically need source directory, destination directory, dependency directory, etc.
Using lein means working with a project, because lein is about building, compiling, libraries dependency management, etc.
Even if you are just learning Clojure or Leiningen and don't really have a project, you must create a project to use or study lein. Because, almost everything assumes the current project, even a empty one.
Leiningen: Create a Project
So, first thing to do to use lein, is to create a project, by:
lein new app xtest
- Creates a new “empty” directory structure (named xtest) at current dir.
◆ lein new app xtest Generating a project called xtest based on the 'app' template.
it'll create a directory structure like this:
CHANGELOG.md doc/ .gitignore .hgignore LICENSE project.clj README.md resources/ src/ test/
Here's what the directory and files mean:
CHANGELOG.md
- dummy markdown file for project change log/notice.
doc/
- directory for your project's documentation.
.gitignore
- dummy file for git ignore pattern.
.hgignore
- dummy file for mercurial ignore pattern.
LICENSE
- dummy file your project's copyright etc info.
project.clj
- important. lein config file for this project.
README.md
- description of the project.
resources/
- libraries, misc files from everything else.
src/
- important. Your Clojure source code go here.
target/
- compiled Clojure/Java files. (this dir will be created when you compile.)
test/
- directory for unit testing code.
Lein Project Config File: project.clj
The file project.clj
is the most important lein file. The files tells lein about your project dependencies, and other info lein needs to do its job.
Here's a default project.clj:
(defproject xtest "0.1.0-SNAPSHOT" :description "FIXME: write description" :url "http://example.com/FIXME" :license {:name "Eclipse Public License" :url "http://www.eclipse.org/legal/epl-v10.html"} :dependencies [[org.clojure/clojure "1.8.0"]] :main ^:skip-aot xtest.core :target-path "target/%s" :profiles {:uberjar {:aot :all}})
This file content is actually Clojure code. It's calling the function defproject
. The defproject
function is defined in Leiningen.
Most of the arguments are :key value
pairs.
Here's some of the most important keys:
• :main
is the entry point of your project. Value is a Clojure namespace. (that is, when lein run
, the function named -main
of this key's value (a namespace) will be called.) The ^:skip-aot
is a Clojure metadata syntax shortcut. 〔see Clojure: Metadata〕 This metadata in lein means don't do ahead-of-time compilation. See project.clj full doc at https://github.com/technomancy/leiningen/blob/stable/sample.project.clj
• :dependencies
is libraries your project depends on. Because Clojure language is running on top of JVM, so we need clojure itself [org.clojure/clojure "1.8.0"]
, at least.
The value is a nested vector. Each element is of the form group_id/artifact_id "version"
What is “artifact” id? what's group id?
A file in the Java Maven repository is called “artifact”, and it has a id.
It also have a group id, usually a reverse domain name.
And it has a version string.
Maven files has a associated config file in XML format, called POM (“Project Object Model”), as “pom.xml”. [http://maven.apache.org/guides/introduction/introduction-to-the-pom.html]
The {artifactId, groupId, version} are from the “pom.xml”
For example, if you have a Maven project, and you want to declare the lib https://github.com/clojure/tools.nrepl as dependency, you can add this content to your pom.xml:
<dependency> <groupId>org.clojure</groupId> <artifactId>tools.nrepl</artifactId> <version>0.2.5</version> </dependency>
In Leiningen's “project.clj” file syntax, this would be:
:dependencies [[org.clojure/tools.nrepl "0.2.5"]]
Note: the following is a convention, but not guaranteed:
- the “group id” is USUALLY the same as the lib's classpath inside the jar file.
- the “artifact id” is USUALLY the same as the class name of the lib's jar file.
• :target-path
is where the compiled files (java class files) will go.
• :profiles
is basically some preferences.
Global Location of Compiled Java Files
Keep in mind that, leiningen will generate many compiled java files at ~/.m2/
. (That directory is the default directory used by Maven. Leiningen follows the convention.)