See more posts

Crystal-lang on raspberry pi

I recently got ahold of a Raspberry PI 5, and wanted to try writing some crystal projects projects for it. To my surprise, I couldn't find an apt source for Raspberry PI OS that included Crystal. Here's the process that I went through to cross compile and install it onto my raspberry pi:

1. Install Crystal dependencies

The page on the project's git wiki describes the dependencies needed.

sh
sudo apt-get install -y \
  automake \
  build-essential \
  git \
  libbsd-dev \
  libedit-dev \
  libevent-dev \
  libgmp-dev \
  libgmpxx4ldbl \
  libpcre3-dev \
  libssl-dev \
  libtool \
  libxml2-dev \
  libyaml-dev \
  lld \
  llvm \
  llvm-dev \
  libz-dev \
  libgc-dev \
  libpcre2-dev

1.5 Install LLVM

You need to have the same or newer version of llvm on the pi as on your cross compilation machine. In my case I compiled the llvm_ext (more on that later) with 17.0.3 as indicated by llvm-config --version

You can get a specific version of llvm on their apt page: https://apt.llvm.org

sh
wget https://apt.llvm.org/llvm.sh
chmod +x llvm.sh
sudo ./llvm.sh 17

Now, select the correct versions so they're available:

sh
sudo update-alternatives --install /usr/bin/llvm-config llvm-config /usr/bin/llvm-config-17 150
sudo update-alternatives --install /usr/bin/clang clang /usr/bin/clang-17 150

2. Download Crystal source

The project's git release page has the latest crystal versions. At the time of writing this is 1.10.1: https://github.com/crystal-lang/crystal/releases

sh
cd /opt
# (as root)
wget https://github.com/crystal-lang/crystal/archive/refs/tags/1.10.1.tar.gz
tar -xzvf 1.10.1.tar.gz

Get this on both the pi and your build machine.

3. Build llvm_ext.o

Now with the source available and a matching version of llvm, on the pi, build the llvm_ext.cc file:

sh
clang -c src/llvm/ext/llvm_ext.cc -o src/llvm/ext/llvm_ext.o `llvm-config --cxxflags`

4. Cross compile crystal:

On your pi, you can get the target name by running llvm-config --host-target . On the PI 5 this shows as aarch64-unknown-linux-gnu

Taking a look at the Makefile shows some build options. Here's what I used to cross compile:

sh
make crystal release=1 interpreter=1 target=aarch64-unknown-linux-gnu

This should also spit out a command that you can use to link the object file on the target device.

5. Transfer the crystal object file to the pi

The crystal.o should be available in the .build folder. I used scp to transfer it to the pi:

scp .build/crystal.o pi.local:/opt/crystal-1.10.1/src/.build/crystal.o

6. Link crystal on raspberry pi os

Now, all that's left is to link the object file on the pi. This is the options that I used when linking:

sh
cc .build/crystal.o -o .build/crystal -W -rdynamic -L../lib/crystal /opt/crystal-1.10.1/src/llvm/ext/llvm_ext.o `"/usr/bin/llvm-config" --libs --system-libs --ldflags 2> /dev/null` -lstdc++ -lpcre2-8 -lm -lgc -lpthread -levent -lrt -lpthread -ldl -lffi

7. Final touches

I added the crystal binary to /usr/bin/crystal :

sh
sudo update-alternatives --install /usr/bin/crystal crystal /opt/crystal-1.10.1/.build/crystal 1

After this, running crystal --version you should get:

text
Crystal 1.10.1 [c6f3552f5] (2023-10-13)

LLVM: 17.0.3
Default target: aarch64-unknown-linux-gnu

and lastly, set the location where crystal looks for library files in the CRYSTAL_PATH env variable:

sh
# /etc/profile
export CRYSTAL_PATH="/opt/crystal-1.10.1/src:lib"

Thanks for reading! See more posts Leave feedback