Tea & Tech (🍵)

Safe-to-Wake Light, Part 4: Clojure on the Pi

January 08, 2020

Our story so far:

  • In Part 1, we introduced Squishy Kitty and set the stage for this project
  • In Part 2, we had some surprise soldering to do
  • In Part 3, we did some proctology and confirmed our soldering was good with some ham-fisted Python execution

Now, we want to class it up a bit. Get some Clojure running. Maybe even get Clojure working some lights!

Installing Java

Java doesn’t ship by default on Raspbian Lite, so we need to install it. After a couple false starts, I landed on using the Zulu Embedded version of Java, by Azul Systems. Installation was pretty straightforward:

$ sudo apt-key adv --keyserver hkp://keyserver.ubuntu.com:80 --recv-keys 0x219BD9C9
$ echo 'deb http://repos.azulsystems.com/debian stable main' | sudo tee /etc/apt/sources.list.d/zulu.list > /dev/null
$ sudo apt update
$ sudo apt install zulu-embedded-8

Because of all my false starts, I needed to add Java to my PATH. I added the following lines to my ~/.bashrc:

export JAVA_HOME=/usr/lib/jvm/zulu-embedded-8-armhf/bin

Afterwards, a quick source ~/.bashrc made Java available from the command line.

$ java -version
openjdk version "1.8.0_152"
OpenJDK Runtime Environment (Zulu Embedded (build 1.8.0_152-b76)
OpenJDK Client VM (Zulu Embedded (build 25.152-b76, mixed mode, Evaluation)

Running Clojure on the Pi

Cool, so Java is installed, but can it run Clojure?

To find out, I took the jar file from my solution to Day 04 of the 2019 Advent of Code challenge, because we spent a lot of time optimizing it ( first with reflection, then with reducers, and then we profiled it to make it even faster). We have a good handle on how fast it runs on a 6-core Intel 8700k, it will be interesting to see how it performs on a 1ghz single-threaded $9 computer.

Let’s give it a shot!

pi@raspberrypi:~ $ java -jar advent2019-day04.jar
Exception in thread "main" java.lang.OutOfMemoryError: Java heap space


All right, so maybe programs that do a bunch of number crunching are not the best choice for an embedded computer.

Let’s make something smaller!

Setting up Clojure on the Pi

If we’re going to be working in Clojure on the Pi, we should have a REPL on the Pi, and so we might as well install Leiningen to do all the things for us.

mkdir ~/bin && cd ~/bin
wget https://raw.githubusercontent.com/technomancy/leiningen/stable/bin/lein
chmod +x ./lein

Then, we need to modify our $PATH again so it can find lein. I edited my .bashrc file such that my PATH now looked like this:

export PATH=~/bin:$JAVA_HOME:$PATH

Source your .bashrc file again, and you should be ready for some embedded Clojure development.

Making a Small Program

Let’s scaffold a new project, squishy-kitty, with the following command:

lein new app squishy-kitty

Once we’ve done that, we can take a look to see what’s inside the default core.clj file:

(ns squishy-kitty.core

(defn -main
  "I don't do a whole lot ... yet."
    [& args]
      (println "Hello, World!"))

A simple “Hello, World!” program. Doesn’t get much smaller than this! Let’s compile it:

$ lein uberjar

Fun tip: If you’re stuck waiting a million years to compile Java on a Pi Zero, consider instead compiling the JAR file on your PC and copying it over to the Pi. Java is “compile once, run anywhere!”

Now that we have a JAR file, let’s try that whole “running Clojure on the Pi” thing again. This time, let’s add the time prefix to see just how long it takes:

$ time java -jar ./target/uberjar/squishy-kitty-0.1.0-SNAPSHOT-standalone.jar
Hello, World!

real    0m18.293s
user    0m17.655s
sys     0m0.599s

We did it! A Clojure program running on the Pi!

But bleh! 18 Seconds to print Hello World!

Hey, it’s still Clojure on the Pi. The productivity benefits will outweigh the runtime cost in the end.

Next time, we’re going to get Clojure-Python interop working. Stay tuned!

Andrew J. Pierce collects yixing teapots and lives in Virginia with his wife, son, and cat Ziggy. You can follow him on Twitter.