Building a GHC cross-compiler for Apple iOS targets

Xcode 5 Notes

These instructions are for Xcode 5, which is now what we're aiming to support as Xcode 4 is no longer available.

If you use ghc-7.6.3 on OS X as your bootstrap compiler, you'll need to pass certain options to clang to work around some problems. A wrapper for this, written in Haskell, can be found at ​https://github.com/ghc-ios/ghc-ios-scripts.

To use it, compile clang-xcode5-wrapper.hs, add it to your path, then edit /usr/local/lib/ghc-7.6.3/settings and change "C compiler command"'s value to "clang-xcode5-wrapper".

(The problem is that 1. GHC tries to run a C pre-processor over Haskell code, and 2. Xcode versions >= 5 use clang instead of gcc, and 3. clang doesn't like Haskell code.).

GHC 7.8 already includes a fix for this, but until that's released you'll have to use this.

2. Scripts

You will need to check out the scripts at ​https://github.com/ghc-ios/ghc-ios-scripts and add the checked out directory to your PATH. You may need to edit these scripts if you are using a different iOS / iOS simulator platform version than the one the scripts are pointed at.

3. Check out GHC

Check out as described at Building and Porting GHC, except:
*use the following for your sync-all to omit dph packages, because Template Haskell doesn't work yet, and dph depends on it
*replace libffi with a newer version that fixes some bugs

6. Make sure your Cabal and cabal-install are new enough

The ghc-ios-scripts directory you checked out earlier contains two wrappers called arm-apple-darwin10-cabal and i386-apple-darwin11-cabal. These will pass the right arguments to cabal, so you can do, for example:

arm-apple-darwin10-cabal install text

If you get errors like "Could not find module Prelude" when installing cabal packages, you probably have cabal's library profiling option on, which our compilation instructions don't enable for GHC's libraries.
You can either disable it by setting

library-profiling: False

in your ~/.cabal/config file, or by passing the --disable-library-profiling like

i386-apple-darwin11-cabal install text --disable-library-profiling

7. Make sure hsc2hs is new enough

The easiest way to do this is as follows, in the ghc build directory:

cd utils/hsc2hs
cabal install

8. Create an Xcode project

Create a new skeleton Xcode project using the wizard, and make sure it runs on your device.

10. Set up your Xcode project for Haskell

Now configure it as follows:

Click on the top node in the project tree, then go to the Build Settings tab. Set Dead Code Stripping to No. This is needed because GHC generates "tables next to code", and without this setting, Xcode thinks the tables are dead code and strips them, causing a crash.

Click on the top node in the project tree, then go to the Build Phases tab. Click on Link Binary With Libraries to open it then click +. Choose libiconv.dylib then click Add.

When you've compiled your Haskell code to a .a (e.g. haskell.a) file, add it to the project anywhere in the hierarchy with Add files to (project) in the right-mouse button menu.

11. Build and run

Run the project again as usual, and Xcode will pick up the haskell.a file and your Haskell code should now run on your iOS device. Anything printed with putStrLn will appear in the Xcode runtime console.

Each time you modify your Haskell code you'll need to re-compile from the command line before re-building in Xcode. It is possible to automate this in Xcode if you wish.

12. Next steps

Take a look at ​https://github.com/ghc-ios/ for patched versions of Hackage packages and other useful things. Ask us if you want to join the ghc-ios project on GitHub, and feel free to raise bugs there.

Loose ends

Template Haskell for cross compilers! Could be done by (in order of increasing complexity):

Evil Splicer / zeroth method

A less powerful template-haskell extension

stage 2 in cross compilers

Packaging with the wrapper scripts and perhaps release of binaries of official ghc releases

Would be nice to not have to disable dead-code removal. (Simon Marlow says "we have special hacks so that you don't have to disable dead-code removal on OS X, in the native code generator and (I presume) in the LLVM backend. Perhaps this just needs to be adapted to work on iOS too?")