Haskell without GMP

Published on

When you compile a Haskell program with GHC, by default your program is linked against the GMP (GNU Multiple Precision Arithmetic) library. GHC uses GMP to implement Haskell’s arbitrary-precision Integer type.

Because GMP is distributed under the L/GPL licenses, this presents a problem if you want to link the executable statically and distribute it without the implications of LGPL.

Here I’ll show how to compile a Haskell program without GMP. The process consists of two steps:

  1. Install a GHC compiled with integer-simple instead of GMP. You may need to compile such a GHC yourself.
  2. Make sure your dependencies do not use GMP.

These instructions are geared towards stack, but it should be clear how to adapt them to other workflows.

Install GHC with integer-simple

integer-simple is a pure Haskell implementation of the subset of GMP functionality.

Because the Integer type is provided by the base library, and the base library is compiled at the same time as GHC itself, we need a different build of GHC to support integer-simple — although that may change at some point.

At the time of writing, FP Complete distributes integer-simple builds for several recent versions of GHC, but only for Windows. To check, look at the current version of stack-setup-2.yaml and search for “integersimple”.

Thus, on Windows you can say

stack setup --ghc-variant=integersimple 8.0.2

and it will download and install the GHC 8.0.2 based on integer-simple.

If you are inside a stack project, add

ghc-variant: integersimple

to stack.yaml so that stack knows which compiler flavor to use. Also, in this case you don’t need to give stack setup the GHC version or --ghc-variant; these will be taken from stack.yaml.

If there is no precompiled integer-simple GHC for your platform or desired GHC version, you’ll have to build it yourself as I describe below.

Compile GHC with integer-simple

These instructions were tested with GHC 8.0.2 on Linux and macOS.

  1. Check the system requirements

  2. Get the GHC source by either cloning the git repo or downloading the source tarball.

  3. Save the template mk/build.mk.sample as mk/build.mk:

    cp mk/build.mk.sample mk/build.mk

    Now, add the following line somewhere in mk/build.mk:

    INTEGER_LIBRARY=integer-simple

    While editing that file, also choose the build profile by uncommenting one of the BuildFlavour = lines.

    • To test the process, use BuildFlavour = quick.
    • Once you are happy with the result, run make distclean and rebuild with BuildFlavour = perf.

    Another option I found useful to set in mk/build.mk is

    BUILD_SPHINX_PDF=NO

    Otherwise, I get errors because I don’t have various exotic TeX packages installed.

  4. Follow the standard build instructions, except the final make install command.

  5. Run make binary-dist to generate the release tarball.

  6. Download the current stack-setup-2.yaml and add a record for your release, such as

    linux64-integersimple-tinfo6:
        8.0.2:
            url: "/home/user/ghc/ghc-8.0.2-x86_64-unknown-linux.tar.xz"
            content-length: 114017964
            sha1: ad38970c4431d44fef38c4696847ba491ef24332

Now you can follow the instructions from the previous section, except replace the stack-setup-2.yaml url with the path or url of your own stack-setup-2.yaml file.

Make sure your dependencies do not use GMP

Some packages depend on GMP through the integer-gmp package.

Fortunately, such packages usually have a Cabal flag to remove this dependency or replace it with integer-simple. The flag itself is usually called integer-gmp or integer-simple.

There are different ways to set these flags. With stack, you can declare the flags in stack.yaml as follows:

extra-deps:
- text-1.2.2.1
- hashable-1.2.5.0
- scientific-0.3.4.10
- integer-logarithms-1.0.1
- cryptonite-0.22

flags:
  text:
    integer-simple: true
  hashable:
    integer-gmp: false
  scientific:
    integer-simple: true
  integer-logarithms:
    integer-gmp: false
  cryptonite:
    integer-gmp: false

The above YAML snippet can be easily turned into a custom snapshot and shared among multiple stack projects if needed.

References

  1. LGPL licensing restrictions on Windows because of integer-gmp
  2. How to use different ghc builds with stack?