Static linking with ghc

Published on

Recently I needed to build a Haskell program that would run on my DigitalOcean box. The problem was that my laptop’s Linux distro (Fedora 22) was different from my server’s distro (Debian jessie), and they had different versions of shared libraries.

I could build my app directly on the server, but I decided to go with static linking instead. I didn’t find a lot of information about static linking with ghc on the internet, hence this article.

First, let’s clarify something. There are two kinds of libraries any Haskell program links against: Haskell libraries and non-Haskell (most often, C) libraries. Haskell libraries are linked statically by default; we don’t need to worry about them. ghc’s -static and -dynamic flag affect that kind of linking.

On the other hand, non-Haskell libraries are linked dynamically by default. To change that, we need to pass the following options to ghc:

-optl-static -optl-pthread

If you are using stack (as I did), the whole command becomes

stack build --ghc-options='-optl-static -optl-pthread' --force-dirty

--force-dirty may be needed because stack may not recognize the options change as a sufficient reason to re-run ghc; this may get fixed in future versions of stack.

The command may fail in case you don’t have some of the static libraries installed. In my case, the dynamic version of the executable had these dynamic dependencies (as reported by ldd):

linux-vdso.so.1 (0x00007ffcb20c2000)
librt.so.1 => /lib64/librt.so.1 (0x00007fa435dc6000)
libutil.so.1 => /lib64/libutil.so.1 (0x00007fa435bc3000)
libdl.so.2 => /lib64/libdl.so.2 (0x00007fa4359be000)
libpcre.so.1 => /lib64/libpcre.so.1 (0x00007fa43574e000)
libgmp.so.10 => /lib64/libgmp.so.10 (0x00007fa4354d6000)
libm.so.6 => /lib64/libm.so.6 (0x00007fa4351cd000)
libgcc_s.so.1 => /lib64/libgcc_s.so.1 (0x00007fa434fb6000)
libc.so.6 => /lib64/libc.so.6 (0x00007fa434bf6000)
libpthread.so.0 => /lib64/libpthread.so.0 (0x00007fa4349d9000)
/lib64/ld-linux-x86-64.so.2 (0x000055571e53e000)

To satisfy them statically, I had to install only three Fedora packages:

pcre-static.x86_64
gmp-static.x86_64
glibc-static.x86_64