# Calling C from Haskell

2017-04-02*
programming, haskell

Yesterday I made a minimal working example of calling C from Haskell, where I call a simple C function to compute the greatest common denominator, or “GCD”. The Haskell portion only serves as a wrapper around the C function. This post is a brief look at the whole setup.

# The Setup

I used ghc 8.0.1, and gcc 5.4.0. 1

## Folder Structure

2017-04-02-calling-c-from-haskell
├── build.sh
├── c
│   ├── gcd.c
│   └── gcd.h
└── hs
├── ffi.hs
└── GCD.hs

2 directories, 5 files


## File Contents

 1  int gcd(int m, int r);
 1 2 3 4 5 6 7 8 9 10  #include "gcd.h" /* Find greatest common divisor. */ int gcd(int m, int r) { if (r == 0) return m; return gcd(r, m % r); }
 1 2 3 4 5 6 7 8 9 10  module GCD where import Foreign import Foreign.C.Types foreign import ccall "gcd" c_gcd :: CInt -> CInt -> CInt f_gcd :: Int -> Int -> Int f_gcd a b = fromIntegral $c_gcd (fromIntegral a) (fromIntegral b)  1 2 3 4  import GCD main :: IO () main = mapM_ (print . uncurry f_gcd) [(8, 12), (30, 105), (24, 108)]  1 2 3 4 5 6 7 8 9  #!/usr/bin/env bash pushd c gcc -c -o gcd.o gcd.c popd pushd hs ghc --make ffi.hs ../c/gcd.o popd # Discussion To compile the example, run the build.sh script. Here is the expected output of the built executable: $ ./hs/ffi
4
15
12


. The gcd() C function is easy to work with because it is a pure function without side effects. You can run the ffi binary against valgrind to make sure that we are not leaking any memory (sample output below).

 $valgrind --error-exitcode=1 --leak-check=yes ./hs/ffi ==14582== Memcheck, a memory error detector ==14582== Copyright (C) 2002-2015, and GNU GPL'd, by Julian Seward et al. ==14582== Using Valgrind-3.12.0 and LibVEX; rerun with -h for copyright info ==14582== Command: ./hs/ffi ==14582== ==14582== Warning: set address range perms: large range [0x4200000000, 0x14200100000) (noaccess) 4 15 12 ==14582== ==14582== HEAP SUMMARY: ==14582== in use at exit: 0 bytes in 0 blocks ==14582== total heap usage: 48 allocs, 48 frees, 60,006 bytes allocated ==14582== ==14582== All heap blocks were freed -- no leaks are possible ==14582== ==14582== For counts of detected and suppressed errors, rerun with: -v ==14582== ERROR SUMMARY: 0 errors from 0 contexts (suppressed: 0 from 0)  ## Caveats Below are some things I tried, but could not get to work. • I tried to delete the gcd.c file by moving the function definition in gcd.c to gcd.h (and delete gcd.c entirely). I compiled the object file with gcc -c -Wall -Wextra -Werror -o gcd.o gcd.h but then I got this error: $ ghc --make ffi.hs ../c/gcd.o
[1 of 2] Compiling GCD              ( GCD.hs, GCD.o )
[2 of 2] Compiling Main             ( ffi.hs, ffi.o )
Linking ffi ...
../c/gcd.o: file not recognized: File format not recognized
collect2: error: ld returned 1 exit status
cc' failed in phase Linker'. (Exit code: 1)

• In GCD.hs you can see the line foreign import ccall "gcd.h gcd"﻿. Instinctively I thought that the gcd.h in ﻿"gcd.h gcd"﻿ served as a kind of disambiguator, for where the gcd() function came from. So then I defined another function named gcd() in a different C header file (gcd_other.h), compiled it separately, but got a “multple definition” error:
 \$ ghc --make ffi.hs ../c/gcd.o ../c/gcd_other.o
[1 of 2] Compiling GCD              ( GCD.hs, GCD.o )
[2 of 2] Compiling Main             ( ffi.hs, ffi.o )
Linking ffi ...
../c/gcd_other.o: In function gcd':
gcd_other.c:(.text+0x0): multiple definition of gcd'
../c/gcd.o:gcd.c:(.text+0x0): first defined here
collect2: error: ld returned 1 exit status
cc' failed in phase Linker'. (Exit code: 1)


1. The version of gcc should not matter at all – actually, any decent C compiler should work.