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:
- Install a GHC compiled with integer-simple instead of GMP. You may need to compile such a GHC yourself.
- 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.
Check the system requirements
Get the GHC source by either cloning the git repo or downloading the source tarball.
Save the template
mk/build.mk.sample
asmk/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 withBuildFlavour = perf
.
Another option I found useful to set in
mk/build.mk
isBUILD_SPHINX_PDF=NO
Otherwise, I get errors because I don’t have various exotic TeX packages installed.
- To test the process, use
Follow the standard build instructions, except the final
make install
command.Run
make binary-dist
to generate the release tarball.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.