Clojure programs typically rely on external libraries in order to run. If you’re writing such a Clojure program, your users would of course need to have these libraries available in order to run your program.
Clojure libraries may make use of and rely on other libraries. If you’re writing such a Clojure library, other programmers who would like to use your library would need some way to install it as well as install any other libs that yours depends upon.
The way these issues are handled with Clojure is:
A Clojure application is typically distributed as a jar file which includes all of the app’s dependencies, including the Clojure jar itself.
A Clojure library is distributed by itself as a jar file. In practice, libraries are available at and automatically fetched as needed from Clojars or Maven Central (or some other repository) by the Leiningen tool (see below), which also recursively fetches any dependencies.
As discussed briefly in the dev environment chapter, the tool most commonly used for managing your Clojure projects is called “Leiningen”. Lein automates a number of project-related tasks. It can:
There’s also a number of available plug-ins that extend lein to support additional commands/tasks.
The Leiningen readme and tutorial explain the details of installing and using lein. A few comments I’d add:
lein
is a standalone program (a shell script which fetches and uses the lein jar, which it installs into ~/.lein/self-installs). You quite often run lein
from inside a project directory.
When you create a new project (ex. lein new my-lib
), lein starts you off by creating a “project.clj” file in your newly-created project directory. This is the project-specific “config file” that lein uses to manage your project.
When you install lein, it creates ~/.lein and ~/.m2/repository directories for its own use. The ~/.m2/repository dir is used for caching jars which lein fetches for use by your projects, and the lein documentation refers to that dir as “the local repository”.
The lein tutorial mentions Ant and Maven. These are Java-land tools for building Java projects (recall, Java files also get compiled to Java bytecode). Lein actually uses the Maven library under the hood. Managing your Clojure projects may entail compiling/ahead-of-time-compiling Clojure (and possibly even Java) code, or making use of Java libraries … and lein automatically manages all of this for you.
The Leiningen github project contains a large sample project.clj file which you may find informative when looking for details on using a particular :option
in your project.clj.
Some quick notes on a few of the lein tasks/commands (see lein help
for the list of all of them):
In addition to lein deps
, you should also never need to explicitly run the compile
or javac
tasks. Lein will take care of running them automatically, if necessary.
If you don’t see what you need in clojure.core, the standard library, or contrib, have a look at the Clojure Toolbox.
And, of course, don’t be afraid to ask for recommendations on IRC or the Clojure mailing list.
If you’ve found a library you wish to use in your project, unless it’s in the Clojure standard library you’ll need to edit your project.clj file and add it to the :dependencies
there so that lein knows your project depends upon it (and will download it for you). The format for specifying a library dependency looks like this:
[group-id/artifact-id version-string]
and is sometimes referred to as the “coordinates” of the library.
The group-id indicates who’s associated with that particular library. The artifact-id is the library name. The group-id is optional if it’s the same as the artifact-id (and this is in fact quite common). The version string follows the common “major.minor.patch” pattern (ex. “1.0.2”; see semantic versioning).
Here are some examples of project coordinates:
[org.clojure/clojure "1.8.0"]
[org.clojure/java.jdbc "0.6.1"]
[sonian/carica "1.0.0"]
[clj-time "0.4.4"]
[environ "0.3.0"]
The convention for most libs at Clojars (the canonical ones that you’ll usually be using) is to have the group-id be the same as the artifact-id. And in that case, the group-id is omitted from the coordinates.
If you see a project at clojars with a group-id like “org.clojars.username”, it usually indicates that the project is a forked version of the canonical one.
There are four names associated with a given library:
Its artifact-id. This is at the top of the library’s project.clj file, first argument to “defproject” (sometimes also preceeded by a group-id then a slash). It’s the “name” of the library.
To use a library, you need its artifact-id (and group-id, if it differs) in your project.clj :dependencies.
Its group-id. This is optionally at the top of the library’s project.clj file, part of the first argument to “defproject” (before the artifact-id and separated from it by a slash). If only an artifact-id is present (no slash), that means the group-id is the same as the artifact-id. Might be the same as the github username.
Its github project name. Most Clojure lib repos are hosted at github, and most of those github projects are named the same as their artifact-id (though this isn’t required). The url for its github project page should usually be used for the project.clj’s :url.
The namespace(s) it provides. A given library’s source code files will each contain an ns
macro at the top, the first argument of which is the namespace that file provides. The namespace name mirrors the directory structure (for example, my-proj’s my-proj.core namespace is represented by my-proj/src/my_proj/core.clj).
So, when using a library:
For standard and contrib Clojure libraries: the namespaces provided all start with “clojure.”. For contrib libs, the artifact-id and github project name are the same. (For the standard libs, there are of course no github project names or artifact-ids.)
For other libraries, which are part of an umbrella project: the typical pattern is: group-id == github org == umbrella project name. The namespace(s) provided may be group-id.artifact-id.*. The github project url is usually github.com/group-id/artifact-id.
For other libraries: the artifact-id, top-level namespace provided, and github project name are all often the same.
Although a given library’s group-id might be the same as the github username the project is under (if it is indeed hosted at github), the group-id and github username are not necessarily related. They very often are though, for example:
the library coordinates | its github url |
---|---|
[sonian/carica “1.0.0”] | https://github.com/sonian/carica |
[clojurewerkz/spyglass “1.0.2”] | https://github.com/clojurewerkz/spyglass |
Note that Clojars page url paths follow the group-id/artifact-id pattern (and leaves out the group-id when it’s the same as the artifact-id).
To use standard libraries in your code you don’t need to touch your project.clj file, since these libs already come with Clojure. Just edit your core.clj file. For example, you can use the clojure.string standard lib like this:
(ns my-proj.core
(:require [clojure.string :as str]))
(defn -main
"docstring goes here"
[& args]
(println (str/reverse "encoded secret!")))
(Note that we’re using “str” here as an alias for clojure.string to save ourselves some typing.)
All the contrib libraries have project pages at github (under https://github.com/clojure), with artifacts (jars) hosted at Maven Central. To use a contrib lib — for example, java.jdbc — we first need to look up its coordinates (which will go into our project.clj). You can find its coordinates on the contrib lib’s github project page (in the README.md). If the info isn’t there, that’s a documentation bug.
Incidentally, if you’d like to see this contrib lib listed at Maven Central, visit there and search for “java.jdbc”. This will tell you that the group-id is “org.clojure”, the artifact-id is “java.jdbc”, and the latest version is “0.6.1” (or whatever the most recent version is).
Add those coordinates to your project.clj’s :dependencies list, for example:
(defproject my-proj "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"]
[org.clojure/java.jdbc "0.6.1"]]
:main my-proj.core)
and make your core.clj’s ns macro look like:
(ns my-proj.core
(:require [clojure.java.jdbc :as j]))
(Note that we’re using “j” here as an alias for clojure.java.jdbc to save ourselves some typing.)
If you’ve found a library you’re interested in at Clojars, the Clojars page for the lib should show you exactly what you need to add to your project.clj’s :dependencies list (it shows info on the most-recently released version).
As noted above: for canonical 3rd-party libs at Clojars, it’s common for the group-id to be the same as the artifact-id, and so there would be no group-id in the coordinates string you add to your project.clj.
In your core.clj file, you’ll often put something like “(:require [lib-name.core :as foo])
” into your ns macro (where “foo
” is some well-chosen short name), and then later use a function from that library like so: (foo/func-name ...)
.
The Clojars page for the lib should also contain a link to the github (or other home) page for the library, which in turn should contain a README showing some example usage. If there is no such link, consider searching for the lib at github and then filing a bug report at the lib’s project page about the issue.
If you want to directly download jar files from Clojars, look in http://clojars.org/repo/.
Search Maven Central for the library you’re interested in, and adjust your project.clj’s :dependencies according to the GroupID, ArtifactID, and Latest Version info shown in the search results. In your ns
macro you’ll use whatever namespaces you need which the library provides.
As for using Java libs which are not registered at Maven Central, see the lein repeatability doc’s “Free-Floating Jars” section.
For a given project, to see the which libraries depend upon which, print out the dependency tree like so:
lein deps :tree
To check if there are newer versions available of your project’s various dependencies, use the lein-ancient lein plug-in. Instructions for use are in its README.