Android and Template Haskell

With the Haskell Cross Compiler for Android we built yesterday, and the knowledge how to Cross Compiling Template Haskell, today we will build the slave process to run on the Android device to allow to us the use of Template Haskell in Android applications.

Prerequisites

As we did for the Raspberry Pi, we need to build iserv-proxy and the iserv library. Please refer to the instructions there if something is unclear.

After checking out the custom ghc branch:

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 -b zw3rk/my-ghc
git reset --hard zw3rk/my-ghc
git submodule update --init --recursive

we need to build the iserv-proxy with the our regular compiler:

ghc/iserv $ cabal install -flibrary -fproxy

and the iserv library with the cross compilers:

ghc/iserv $ armv7-linux-androideabi-cabal install -flibrary
ghc/iserv $ arch64-linux-android-cabal install -flibrary

Building GHCSlave for Android

Similar to the Android application we built yesterday, we need to build a haskell library and a wrapper to use the library from the Android app.

The code for the GHCSlave android app can be found in the zw3rk/ghc-slave repository in the android folder.

Building the static library for android is a simple as

aarch64-linux-android-ghc -odir arm64-v8a -hidir arm64-v8a \
   -staticlib -threaded -liconv -lcharset \
   -L/path/to/libffi/aarch64-linux-android/lib -lffi \
   -o app/hs-libs/arm64-v8a/libhs.a -package iserv-bin \
   app/src/main/hs/LineBuff.hs
armv7-linux-androideabi-ghc -odir armeabi-v7a -hidir armeabi-v7a \
   -staticlib -threaded -liconv -lcharset \
   -L/path/to/libffi/armv7-linux-androideabi/lib -lffi \
   -o app/hs-libs/armeabi-v7a/libhs.a -package iserv-bin \
   app/src/main/hs/LineBuff.hs

Note that we need -threaded and the iserv-bin package. Threaded because the startSlave function calls forkIO to start the slave in a separate thread. And the iserv-bin package to embed it into the static library. The LineBuff.hs is only necessary to set the haskell line buffering and get instant feedback, when piping stdout and stderr into a TextView.

With the libraries built for both architectures, starting the application from android studio should present us with

Figure 1: GHCSlave running on android device

Figure 1: GHCSlave running on android device

Compiling some Template Haskell

We will build a sample application that uses the gitrev package to show the git revision it was built from in a TextView. Pretty similar to the Hello World application from yesterday, it will however use Template Haskell.

The application can be found at zw3rk/hs-hello-templatehaskell.

First we will need to install the patched gitrev package

git clone https://github.com/mobilehaskell/file-embed.git
(cd file-embed && armv7-linux-androideabi-cabal install)
(cd file-embed && aarch64-linux-android-cabal install)

Following the example from yesterday, and using the following Lib.hs

module Lib where
import Development.GitRev (gitHash)
import Foreign.C (CString, newCString)
foreign export ccall "gitrev" cgitrev :: IO CString
-- | turn $gitHash into a c string.
cgitrev = newCString $gitHash

and compiling it via the GHCSlave will yield the libhs.a.

aarch64-linux-android-ghc -odir arm64-v8a -hidir arm64-v8a \
   -staticlib \
   -o app/hs-libs/arm64-v8a/libhs.a -package gitrev \
   app/src/main/hs/Lib.hs \
   -fexternal-interpreter \
   -pgmi $HOME/.cabal/bin/iserv-proxy -opti10.0.1.21 -opti500
aarch64-linux-android-ghc -odir arm64-v8a -hidir arm64-v8a \
   -staticlib -liconv -lcharset \
   -L/path/to/libffi/aarch64-linux-android/lib -lffi \
   -o app/hs-libs/arm64-v8a/libhs.a -package gitrev \
   app/src/main/hs/Lib.hs
armv7-linux-androideabi-ghc -odir armeabi-v7a -hidir armeabi-v7a \
   -staticlib \
   -o app/hs-libs/armeabi-v7a/libhs.a -package gitrev \
   app/src/main/hs/Lib.hs \
   -fexternal-interpreter \
   -pgmi $HOME/.cabal/bin/iserv-proxy -opti10.0.1.22 -opti500
armv7-linux-androideabi-ghc -odir armeabi-v7a -hidir armeabi-v7a \
   -staticlib -liconv -lcharset \
   -L/path/to/libffi/aarch64-linux-android/lib -lffi \
   -o app/hs-libs/armeabi-v7a/libhs.a -package gitrev \
   app/src/main/hs/Lib.hs

Note: due to a bug in how ghc currently expects the GHCSlave to find libiconv and libcharset=/, we invoke the compiler twice. The first time compiling/ =Lib.hs into =Lib.o=/, and the second time providing all the libraries that should be linked into the final archive. At that point we don’t need the/ -fexternal-interpreter anymore, as we already have an up-to-date copy of =Lib.o=/. This limitation should soon be lifted. An alternative is to copy/ libiconv=/,/ =libcharset=/, and/ =libffi into the app/hs-libs/<arch> folder for each folder and link them similar to the hs-lib in the =CMakeLists.txt=/./

With all that setup, we can simply launch the android application from android studio and see the git hash as expected.

Figure 2: Hello Template Haskell app running on android device

Figure 2: Hello Template Haskell app running on android device

With this we now have a fully functioning Haskell Compiler with Template Haskell support. Another day we will have a look at doing something a little more interactive than just displaying a string of text.