Creating a Clojure project

How to create a Clojure project, main files, paths and dirs

First things first, get the Clojure command-line tool. You should be able to run clj -M -e "(prn :hello-world!)" anywhere.

Let's create a empty directory to work:

~ $ mkdir pinheiro
~ $ cd pinheiro
~/pinheiro $

Now let's create the deps.edn file.

{:paths   ["src"]
 :deps    {org.clojure/clojure {:mvn/version "1.10.1"}}}

There are 2 main keys in deps.edn:

Clojure, like java, uses the notion of namespaces to organize code. It isn't a good pattern to use single-segment namespaces, for example, just pinheiro.

We will start by creating the namespace pinheiro.main.

It needs to be in src/pinheiro/main.clj from the project root. Once you declared in deps.edn that src is where your classpath starts, we say that it's pinheiro/main.clj in your classpath.

At this moment you should have a structure like this:

~/pinheiro $ tree
├── deps.edn
└── src
    └── pinheiro
        └── main.clj
~/pinheiro $

The src/pinheiro/main.clj should contain something like this:

(ns pinheiro.main)

(defn -main
  [& argv]
  (prn ["Hello, here my args: " argv]))

Now, we can call clj -M -m pinheiro.main hello world

~/pinheiro $ clj -M -m pinheiro.main hello world
Downloading: org/clojure/clojure/1.10.1/clojure-1.10.1.pom from central
Downloading: org/clojure/spec.alpha/0.2.176/spec.alpha-0.2.176.pom from central
Downloading: org/clojure/core.specs.alpha/0.2.44/core.specs.alpha-0.2.44.pom from central
Downloading: org/clojure/pom.contrib/0.2.2/pom.contrib-0.2.2.pom from central
Downloading: org/clojure/pom.contrib/0.2.2/pom.contrib-0.2.2.pom from central
Downloading: org/clojure/clojure/1.10.1/clojure-1.10.1.jar from central
Downloading: org/clojure/spec.alpha/0.2.176/spec.alpha-0.2.176.jar from central
Downloading: org/clojure/core.specs.alpha/0.2.44/core.specs.alpha-0.2.44.jar from central
["Hello, here my args:" ["hello" "world"]]
~/pinheiro $

All deps downloads will be cached, in general, in ~/.m2 directory. If you run again, it will just run.

~/pinheiro $ clj -M -m pinheiro.main hello world
["Hello, here my args:" ["hello" "world"]]
~/pinheiro $


These file/dirs you should not commit:

As mvn and pom.xml, clj and deps.edn is a deterministic package manager. Given a deps.edn, it will ALWAYS use the same tree of dependencies, so it DOES NOT NEED A LOCK FILE.

APPENDIX: Clojure direct from java

You do not need any Clojure command-line to run Clojure programs. If you know your classpath, you can run it directly from java

You can use clj -Spath and save your classpath from stdout into a file, then run java using this classpath. You need to call clojure.main class will build and run pinheiro.main for you.

~/pinheiro $ clj -Spath > classpath.txt
~/pinheiro $ java -cp "$(cat classpath.txt)" clojure.main -m pinheiro.main hello world

You can also build Clojure in AoT. compile is a Clojure function that receives a namespace as a symbol and compiles all classes needed to run that namespace, saving its classes in classes dir.

Then you need to include that classes directory into classpath. With this, you can directly call you namespace from java.

~/pinheiro $ mkdir classes
~/pinheiro $ clj -M -e "(compile 'pinheiro.main)"
~/pinheiro $ echo "classes:$(clj -Spath)" > classpath.txt
~/pinheiro $ java -cp "$(cat classpath.txt)" pinheiro.main hello world