In this blog post, I am going to show you how to link a C library in Haskell. Each step is kept as simple as possible in order to focus on the overall goal.
- develop a small C program
- generate two static C libraries from the C program
- merge both libraries into one
- develop a small Haskell program
- let GHC link to the merged C library
- use the functions exported by the C library within Haskell
The code snippets can be found here.
The C program
The C program is going to be extremely simple.
main.c is calling a library function and printing the result:
The library function
liba_func() is provided by, who guessed it,
The latter refers to
libb_func() in order to carry out its work.
The corresponding (educational) Makefile:
The static libraries
We can convert
lib*.o into static libraries using
This tool creates a so called archive file which is basically just a collection of object files.
In our case, both archives each contain only one object file.
For completeness, we’ll let
gcc link again the static libraries instead of the object files for
One can inspect the archive content with
We see that
libb.a defines the function (“symbol”)
libb_func and expects the symbol
The latter comes from
math.h and the actual function is linked by
-lm in the Makefile’s
Merging the libraries
The obvious way to merge both static libraries is to create a single archive from both object files (i.e.
ar -csr libab.a liba.o libb.o).
However, I am going to assume the libraries come as is and the object files are not available.
This allows me to show a trick with
The issue with
ar is that you cannot simply create an archive by listing archive files instead of object files on the command line.
ar will happily archive the input files without looking into them and thus create a nested archive.
The inner archives are not accessible anymore:
We can however ask
ar to add the contents of one archive to the current one using the ADDLIB directive from GNU ar’s “librarien” compatibility mode.
In this mode,
ar is controlled with a script which we can also simply pipe from the command line.
This time, inspecting the archive yields the exported symbols (functions) as expected. The necessary Makefile changes:
The Haskell program
The Haskell program is going to be straight forward. I’ll let stack create the a simply project for me
Linking to the C library
stack generates a Cabal file within the project.
This file is kind of like the Makefile of a Haskell app.
We can define GHC options within that file.
In order to tell GHC to link to an external library, we have to give a library path and a library name (pretty similar to GCC).
This is done by
So we could simply use stack’s
ghc-options parameter to add these.
However, it is recommended to use
This is how we need to adapt the cabal file:
../c is the path to the aforementioned C program which contains
The file name’s prefix is striped so that
Using the C library
We are going to make a wrapper Haskell library (file) that exposes the functions of the C library. Calling the actual C functions is done trough Haskell’s Foreign Function Interfarce. The source code is simple and listed below. You can google around to find lots of information about suing the FFI in more detail.
Now that we have the Haskell function
liba_func at our disposal, we can go ahead and call in
This is the outcome:
Note how the pure Haskell function
liba_func :: Double -> Double produces side effects!
This is quite expected.
The Haskell compiler cannot look into the compiled C functions and cannot differentiate pure from impure code.
It merely links the foreign functions where asked to.
The programmer needs to provide this information.
In this case, it should have been
liba_func :: Double -> IO Double to accommodate for the
printf in the C function.
Done! You just learned how to combined C & Haskell! Well, at least some part of it.
You can retrace all steps by looking into the commit history of this Git repo.