loading...
Cover image for Using Elm on a Raspberry Pi

Using Elm on a Raspberry Pi

danielkun profile image Daniel Albuschat ・5 min read

Running Elm on your Raspberry Pi

Elm is an awesome programming language that makes you feel comfortable, empowered and safe. Since I went out on a journey to put a Kubernetes cluster on a few Raspberry Pis and built a frontend for a few experiments (see kube-alive), I had the need to compile Elm code on Raspberry Pis. Unfortunately, there are no official Elm binaries for the arm CPU architecture distributed via npm or any other way.

    daniel@kubepi-red:~ $ npm install elm
    > elm@0.18.0 install /home/daniel/node_modules/elm
    > node install.js

    Unfortunately, there are currently no Elm Platform binaries available for your operating system and architecture.

    If you would like to build Elm from source, there are instructions at https://github.com/elm-lang/elm-platform#build-from-source

    npm WARN This failure might be due to the use of legacy binary "node"
    npm WARN For further explanations, please read
    /usr/share/doc/nodejs/README.Debian

So I set out to compile Elm for arm using a Raspberry Pi on raspbian (stretch) myself. This turned out to be rather tedious, because of two factors that are a bad combo: Not all versions of Elm dependencies (especially Cabal) work as expected and are compatible. And compiling one version of Cabal takes literally days. (Well, at least a bit more than 24 hours.)

The good news is that it is pretty straight-forward and should work without hassles if you follow the steps in this tutorial and use the exact same versions I did. It will still take approximately two days to install and compile everything that you need. The even better news is that I already did this for you, and can provide a much faster way to run Elm on your Raspberry Pi via docker.

The shortcut: Use a prebuilt docker image

If you don't want to wait that long to build Elm, you can use my pre-built docker image that you can run on your raspi. Find it on Docker Hub as danielkun/elm-raspbian-arm32v7.

Just run

docker run -it danielkun/elm-raspbian-arm32v7 bash

and inside that container you can use the elm commands as you are used to. Note that everything that happens in this docker run session will be discarded once you close the shell. That's why you should mount a directory as a volume into the container - these changes are made directly to your filesystem and will be permanent.

To run the elm docker container with the current directory mounted to /code and everything set up correctly, execute

docker run -it --rm -v "$(pwd):/code" -w "/code" -e "HOME=/tmp" -u $UID:$GID -p 8000:8000 danielkun/elm-raspbian-arm32v7

If you want to stick with this for longer, you can make your local "elm" command an alias for this, and all parameters will be appended, so that you can run "elm make", "elm reactor", etc. as if it was installed on your local machine. Set up the alias like this:

alias elm='docker run -it --rm -v "$(pwd):/code" -w "/code" -e "HOME=/tmp" -u $UID:$GID -p 8000:8000 danielkun/elm-raspbian-arm32v7 elm'

(Credit goes to maport from https://github.com/maport/docker-elm for this trick)

Building Elm yourself

If you're not satisfied with using a docker image, you can still build Elm yourself, if you bring enough time.

Elm does only have a few platforms it depends on, but these are massive, and not all can be obtained as binaries:

  • llvm-3.5 (for ghc, can be obtained as binary)
  • ghc 7.10.3 (can be obtained as binary)
  • cabal-install 1.22.6 (must be compiled, hence slooooow to install)

Besides these larger dependencies, there are a few packages that you can install via apt, and many that will be downloaded and compiled while building Elm via cabal.

So let's start with installing the packages that we can obtain from apt, since this is the easiest part:

sudo apt-get update && sudo apt-get install -y wget curl make libgmp-dev libnss3 apt-utils libnss-lwres libnss-mdns netbase ca-certificates cmake g++ libtinfo-dev git zlib1g-dev

As part of the building process and to use the elm commands later, we need a few directories for llvm, cabal and finally elm in our PATH:

echo 'export PATH="$PATH:$HOME/elm/llvm-3.5/bin:$HOME/.cabal/bin:$HOME/elm/Elm-Platform/0.18/.cabal-sandbox/bin/"' >> ~/.bashrc && source ~/.bashrc

Now, download everything we'll need later:

mkdir ~/elm-downloads && cd ~/elm-downloadswget http://releases.llvm.org/3.5.2/clang+llvm-3.5.2-armv7a-linux-gnueabihf.tar.xz
wget https://downloads.haskell.org/~ghc/7.10.3/ghc-7.10.3-armv7-deb8-linux.tar.bz2
wget http://www.haskell.org/cabal/release/cabal-install-1.22.6.0/cabal-install-1.22.6.0.tar.gz

Then extract the packages in a dedicated directory for building Elm:

mkdir ~/elm && cd ~/elm
tar xf ~/elm-downloads/clang+llvm-3.5.2-armv7a-linux-gnueabihf.tar.xz && mv clang+llvm-3.5.2-armv7a-linux-gnueabihf llvm-3.5
tar xf ~/elm-downloads/ghc-7.10.3-armv7-deb8-linux.tar.bz2
tar xf ~/elm-downloads/cabal-install-1.22.6.0.tar.gz

LLVM is now ready to be used from where it has been extracted. GHC, however, needs to be installed:

cd ~/elm/ghc-7.10.3/
./configure
make install

That should be fairly quick, since it's not building anything, but just copies around files. Next, go for the hard (and time-consuming) task: Build cabal-install

cd ~/elm/cabal-install-1.22.6.0
./bootstrap.sh

Now grab a coffee. And your wife and kids and go outside for a few hours. Then go to sleep and wake up the next morning, go to work and then, after work, it might have finished. Mind you that I used the most recent Raspberry Pi 3 and it still took around 10 hours or so. If you have a Raspberry Pi 2, for example, it might take even longer.

But it will finish eventually. And when it did, you can download and compile Elm now. (Remember: Your PATH is already set up correctly.) Note that I had to fix some small issue with the installation script, since it sets "split-Objs: True", which seems to be not compatible with the GHC or cabal version, so I changed it to "split-Objs: False".

curl -sSL https://raw.githubusercontent.com/elm-lang/elm-platform/master/installers/BuildFromSource.hs \
 | sed "s/split-objs: True/split-objs: False/" > BuildFromSource.hs && runhaskell BuildFromSource.hs 0.18

This, again, takes about a day or so. I haven't measured exactly. It takes so long because there are quite a few cabal dependencies that will be downloaded and built before Elm is built.

Hooray! You should have working `elm' commands now! Have fun hacking away on your raspi and make some cool IoT projects.

Finally, you can clean up quite a bit by removing no longer necessary downloads and temporary files:

rm -rf ~/elm-downloads ~/elm/ghc-7.10.3 ~/elm/cabal-install-1.22.6.0

Elm for the win!

Discussion

pic
Editor guide
Collapse
nelsonic profile image