on
A Haskell Cross Compiler for Raspberry Pi
After setting up our Raspberry Pi and building the raspbian SDK. Today we will build a Haskell cross compiler (GHC) for the Raspberry Pi, to be used together with the SDK.
We will use a custom GHC branch, as not all necessary patches have yet
landed yet in the upstream repository. Alternatively you can use the
official GHC master
branch and apply the patches manually with arc patch
.
Prerequisites
Make sure you have a ghc
and cabal
installed. You can download a
recent version from downloads.haskell.org. You will also need alex
and
happy
:
cabal install alex happy
This should produce ~/.cabal/bin/alex
and ~/.cabal/bin/happy
.
Due to an incompatibility between the latest version of libffi (from
2014), and recent llvm versions, which only understand the unified arm
assembly syntax, we need to build a custom libffi version. With the
raspbian SDK’s prebuilt/bin
in PATH
this should be as simple as:
git clone https://github.com/libffi/libffi.git
cd libffi
./autogen.sh
CC="arm-linux-gnueabihf-clang" CXX="arm-linux-gnueabihf-clang" \
./configure \
--prefix=/path/to/libffi/arm-linux-gnueabihf \
--host=arm-linux-gnueabihf \
--enable-static=yes --enable-shared=yes
make && make install
This will build and place the libffi
header and libraries into
/path/to/libffi/arm-linux-gnueabihf
.
Building GHC
Ensure that ghc
, alex
, happy
, cabal
, as well as your Raspbian
SDK are in your PATH
. If not, export PATH
appropriately:
export PATH=$HOME/.cabal/bin:$PATH
export PATH=/path/to/bin/ghc:$PATH
export PATH=/path/to/raspbian-sdk/prebuilt/bin:$PATH
Next, we will obtain the patched GHC source via git
:
git clone --recursive git://git.haskell.org/ghc.git
cd ghc
git remote add zw3rk https://github.com/zw3rk/ghc.git
git fetch zw3rk
git checkout zw3rk/my-ghc -b my-ghc
git submodule update --init --recursive
Note: the custom my-ghc
branch contains a few patches
(D3352/,/
D3443, /
D3448,/
D3502/,/
D3579/,/
D3591/) on top of the GHC
master branch that are not yet landed./
Building GHC
for arm-linux-gnueabihf
and installing it alongside
clang
in the raspbian sdk should require only the following now
# set paths
export RASPBIAN_SDK=/path/to/raspbian-sdk/
export LIBFFI=/path/to/libffi/arm-linux-gnueabihf
# Boot up the build system
./boot
# Configure a GHC that targets the Raspberry Pi
./configure --target=arm-linux-gnueabihf \
--prefix=$RASPBIAN_SDK/prebuilt \
--with-system-libffi \
--with-ffi-includes=$LIBFFI/include \
--with-ffi-libraries=$LIBFFI/lib
# Create a mk/build.mk and set the BuildFlavour to quick-cross
sed -E "s/^#(BuildFlavour[ ]+= quick-cross)$/\1/" \
mk/build.mk.sample > mk/build.mk
# Compile and install ghc
make -j && make install
This will likely take approximately 30–60 minutes depending on your
hardware. If everything went right, you will find
arm-linux-gnueabihf-ghc
in /path/to/raspbian-sdk/prebuilt/bin
.
We will wrap up by trying out our brand new Haskell cross compiler.
Compiling Hello World
Let us create a very simple Hello.hs
similar to the hello.c
we
created when trying out clang
from the SDK’s toolchain.
module Main where
main :: IO ()
main = putStrLn "Hello World!"
Compiling it should be as trivial as saying
arm-linux-gnueabihf-ghc Hello.hs
Assuming that /path/to/raspbian-sdk/prebuilt/bin
is still in your
PATH
.
Running Hello World
All that is left now, is to copy the binary over to the Raspberry Pi
scp Hello pi@raspberrypi:
and executing it
ssh pi@raspberrypi ./Hello
Next we will look at Haskell’s package management with Cabal with an eye on cross compilation.