What are the Clojure Tools?
The Clojure Tools are a group of convenience tools which currently consist of:
Clojure CLItools.build
The Clojure Tools.
were designed to answer some of the following questions:
- How do I install Clojure? (
Clojure CLI) - How do I run a Clojure program? (
Clojure CLI) - How do I manage Clojure packages (dependencies)? (
Clojure CLI) - How do I configure a Clojure project? (
Clojure CLI) - How do I build Clojure for production? (
tools.build)
The rest of this post will dig into each of these tools.
Clojure CLI
The Clojure CLI is a CLI program. Here is what it looks like to use the
Clojure CLI and some of the things it can do:
Run a Clojure repl
clj
Run a Clojure program
clj -M -m your-clojure-program
manage Clojure dependencies
clj -Sdeps '{:deps {bidi/bidi {:mvn/version "2.1.6"}}}'
Like all Clojure programs, the Clojure CLI is built on a few libraries:
- clj/clojure - a bash script
- tools.deps a clojure library (commonly referred to as
deps) - deps.edn - an edn file with a specific structure
The following sections will provide overviews of each of the above tools.
The Clojure CLI is invoked by calling either clj or clojure shell commands:
# clj
clj -M -m your-clojure-program
# clojure
clojure -M -m your-clojure-program
Under the hood, clj actually calls clojure. The difference is that clj
wraps the clojure command with a tool called rlwrap. rlwrap
improves the developer experience by making it easier for you, a human, to type
in the terminal while you're running your Clojure REPL. However, even though
it's easier for you to type, rlwrap can make it hard to compose the clj
command with other tools. As a result, it's a common practice to use clojure
in production/ci environments .
Additionally, not all environments have access to rlwrap so it's another
dependency you have to install.
Okay, so they do the same thing. What do they do? clj/clojure has one job:
run Clojure programs against a classpath.
The next sections will outline the tools that make up the Clojure CLI tool.
clj/clojure
If you dig into the clj/clojure is just a bash script which ultimatley calls
a command like this:
java [java-opt*] -cp classpath clojure.main [init-opt*] [main-opt] [arg*]
Thus, the Clojure CLI tool makes it easier to run Clojure programs. It saves
you having to type out a gnarly Java command and make it work on different
environments (windows, linux, mac etc). However, it orchestrates the building
of the classpath by calling out to tools.deps.
tools.deps
tools.deps is a Clojure libary responsible for managing your dependencies.
It does the following things:
- reads in dependencies from a
deps.ednfile - resolves the dependencies and their transitive dependencies
- builds a classpath
What's interesting about this program is that it's just a Clojure library.
This means that you can use it outside of the Clojure CLI.
The other thing that makes tools.deps great is that it's a small and
focused library. Why this is great is that if something goes wrong it's easy
to read and learn the library in a short period of time.
deps.edn
deps.edn is just an edn file where you configure your project and specify
project dependencies. You can think of it like Clojure's version of
package.json. The deps.edn file is a Clojure map
with a specific structure. Here's an example of some of the properties of
a deps.edn file:
{:deps {...}
:paths [...]
:aliases {...}}
As you can see, we use the keywords :deps, :paths and :aliases and more
to start to describe your project and the dependencies it requires.
As we noted above, deps.edn is read in when you run clj/clojure and tells clj/clojure
which dependencies are requires to run your project.
Tools.Build
tools.build is a Clojure library with functions for building clojure projects.
For example, build a jar or uberjar.
The way you would use tools.build is by writing a separate program inside
your app which knows how to build your app. The convention is to create a
build.clj file in the root of your project. Import tools.build and use
the functions provides by tools.build to build your program.
The 3 main types of Clojure programs one might build into 3 sub categories:
- A
tool - A
library - An
app
When you run your build.clj file, you will use Clojure CLI's -T switch.
The -T switch is meant to run general clojure programs via the Clojure CLI
and since build.clj is a separate program, distinct form the app you are
writing, you would run it via the -T switch.
You would use -T for Clojure programs that you want to run as a "tool". For
example, deps-new is a Clojure library which creates new Clojure projects
based on a template you provide. This is a great example of a Clojure project
which is built to be a "tool".
I don't want to go into more detail about -T now because that means we would
have to dive into other Clojure CLI switches like -X and -M. That's for
another post. On to the Installer!
Installer
The "Clojure CLI Installer" is a fancy way of referring to the brew tap used
to install Clojure on mac and linux machines. As of February 2020, Clojure
started maintaining their own brew tap. Thus, if you installed the
Clojure CLI via
brew install clojure
you will likely want to uninstall clojure and install the following:
brew install clojure/tools/clojure
In all likelihood, you would probably be fine with brew install clojure as it
will recieve updates. However, while brew install clojure will still see some
love, it won't be as active as the clojure/tools/clojure tap.
clj v lein v boot
This section will provide a quick comparison of clj, lein and boot.
Firstly, all of the above tools are more or less addressing the same problems in their own way. Your job is to choose the one you like best.
If you're curious which to choose, my answer is the Clojure CLI.
The reason I like the Clojure CLI is because the tool is simple.
You can read through clj and tools.deps in an afternoon and understand
what they are doing. The same (subjectively of course) cannot be
said for lein or boot. I will note that Clojure CLI's API is not
straightforward and can be confusing.
Secondly, the Clojure Tools promote libraries over frameworks. This is
important when working with a language like Clojure because it really does
reward you for breaking down your thinking.
Finally, the Clojure community is really leaning into
building tools for Clojure CLI. For example, where lein used to have significantly
more functionality, the community has built a ton of incredible tools that
will cover many of your essential requirements.