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.
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
wget https://apt.llvm.org/llvm.sh
chmod +x llvm.sh
sudo ./llvm.sh 17
Now, select the correct versions so they're available:
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
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:
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:
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:
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
:
sudo update-alternatives --install /usr/bin/crystal crystal /opt/crystal-1.10.1/.build/crystal 1
After this, running crystal --version
you should get:
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:
# /etc/profile
export CRYSTAL_PATH="/opt/crystal-1.10.1/src:lib"