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.