Skip to content

Instantly share code, notes, and snippets.

@thumphries
Created June 2, 2016 00:54
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save thumphries/051b293f25f06c45f0c858f628c84b9e to your computer and use it in GitHub Desktop.
Save thumphries/051b293f25f06c45f0c858f628c84b9e to your computer and use it in GitHub Desktop.
GHC cross-compilation

Notes on cross-compiling GHC for a Darwin target.

TL;DR I managed to get most of a stage1 to build. I got a linker failure during ghc-prim, but most of the libraries had already built successfully, including some C FFI-heavy packages like bytestring. I suspect my toolchain was just in the wrong spot, and/or libraries misconfigured.

  • We need a normal host GCC toolchain (build-essential), autoconf, happy, alex, and a platform copy of GHC (the Stage0).
  • As per the GHC CrossCompiling page on Trac, we need a GCC crosschain. I used osxcross.
  • We also need binutils, which don't come with osxcross. I might have gone wrong here: I built these using the host's GCC chain, with --target=x86_64-apple-darwin. The configure script confirmed that we were cross-compiling, but still proceeds with the 'can we run a GCC-compiled file' check, which suggested to me that this was the right way to go. We need to run objdump and readelf on the host, so it makes sense to use the host GCC. But not sure.
  • We need ncurses and tinfo headers. Supposedly ncurses is just for GHCI (which we don't need), while tinfo ends up in the terminfo library, which we build with our Stage1 and link into target binaries.
  • We need a GHC source tree, checked out for the whatever version we want to build. Their submodules are broken if you clone the copy on GitHub, so either clone it direct from Haskell.org or paste some git config into a terminal (find the relevant lines on the Getting The Sources page on Trac). Check out the tag you want (ghc-7.10.3-release in my case), and don't forget to synchronise your submodules (git submodule init; git submodule update). I wasted about 30 minutes googling CPP errors because my submodules all pointed to HEAD.
  • We need a mk/build.mk to disable Stage2. Usually the Stage0 builds a Stage1, which then builds a Stage2. In our case, the Stage1 produces binaries that our host platform can't run, so the Stage2 wouldn't be useful. I just used the preset quick-cross, note that this builds with -O0 and ships integer-simple instead of integer-gmp. We want to successfully build and use integer-gmp before we can use this cross-compiler in production. However, those are problems for after `"Hello world!"
  • configure.ac checks for some Xcode artefacts when the target is set to Darwin. This seems to be a bug, it probably should only check when the host is Darwin. I just edited that segment out of the configure script. If it detects an old version of Xcode, it disables split-objs.
  • ./boot - run the perl script to do library configuration things
  • autoreconf to generate configure
  • Configure for cross-compilation. As the CrossCompiling page says, --target=x86_64-apple-darwin is the least we need here. In my case, osxcross (or the dodgy Dockerfile I used to install it) does not prefix the toolchain in the correct way, so I had to manually override the locations of ghc, ld, ar, as, ranlib, objdump, and readelf. We also need install_name_tool on PATH.
  • make

There were lots of subtly wrong things in my setup here. It's not really surprising that it died with a linker error; it might have been using the wrong ar or as or ld; I'm also pretty sure my binutils weren't where I thought they were. When trying again, I'll use osxcross to bootstrap a clean install of gcc, and make sure all my toolchain have the proper x86_64-apple-darwin prefix. That way the host and target toolchains can share a namespace in the way that almost every build script seems to expect.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment