Search code examples
haskellghcffighcihaskell-stack

Is there a needed GHC option for an executable using the FFI?


I have a module Main in Main.hs. The program uses the FFI (in particular, FunPtr).

When I run stack exec ghci and I load the module (:l src/Main.hs), it works perfectly.

However when I compile the module to an executable and I run the executable, I get a crash, namely a segmentation fault.

Therefore I'm wondering whether I need to compile with a certain option. Is there a specific option to use when dealing with the FFI ? I tried -O0, -fllvm, no way. Maybe stack exec ghci includes an option that could be used with GHC ?

Also, is there a debug option that one can set to GHC in order to run the executable with gdb ? I tried the -g option but gdb does not find debugging symbols. EDIT This point is solved: gdb finds debugging symbols when I compile with stack exec -- ghc -g -rtsopts src/Main.hs.

I'm on Linux Ubuntu and I'm using GHC 8.2.2.

EDIT

Here is a minimal program that reflects the structure of my real program. This one works fine (in GHCI or as an executable), but I include it nevertheless.

helloffi.c:

#include <stdlib.h>

double** evalf(double (*f)(double), double x){
    double** out = malloc(2 * sizeof(double*));
    for(unsigned i=0; i<2; i++){
        out[i] = malloc(2 * sizeof(double));
        out[i][0] = (*f)(x);
        out[i][1] = (*f)(x+1);
    }
    return out;
}

double sumpointer(double** pptr){
    double x=0;
    for(unsigned i=0; i<2; i++){
        for(unsigned j=0; j<2; j++){
            x += pptr[i][j];
        }
    }
    return x;
}

main module of the library, Lib.hs

{-# LANGUAGE ForeignFunctionInterface #-}
module Lib
  where
import           Foreign.C.Types       
import           Foreign.Ptr           (Ptr, FunPtr, freeHaskellFunPtr)

type CFunction = CDouble -> IO CDouble

foreign import ccall "wrapper" functionPtr 
    :: CFunction -> IO (FunPtr CFunction)

foreign import ccall "evalf" c_evalf
    :: FunPtr CFunction
    -> CDouble
    -> IO (Ptr (Ptr CDouble))

fun2cfun :: (Double -> Double) -> CFunction
fun2cfun f x = 
    return $ realToFrac (f (realToFrac x))

evalFun :: (Double -> Double) -> Double -> IO (Ptr (Ptr CDouble))
evalFun f x = do
    fPtr <- functionPtr (fun2cfun f)
    result <- c_evalf fPtr (realToFrac x)
    freeHaskellFunPtr fPtr
    return result

foreign import ccall "sumpointer" c_sumpointer
    :: Ptr (Ptr CDouble) -> IO CDouble

module Main.hs, to be compiled

module Main
  where
import           Lib

main :: IO ()
main = do
    x <- evalFun (\x -> x*x) 2
    y <- c_sumpointer x
    print y

Solution

  • Well, this is not really an answer to the question but I have painfully solved the issue and I think it might be helpful for others. It is worth to share. So I post a minimal example showing the problem. A very minimal example.

    helloffi/
    ├── C
    │   ├── array.c
    │   ├── helloffi.c
    │   └── helloffi.h
    ├── helloffi.cabal
    ├── Setup.hs
    ├── src
    │   ├── Lib.hs
    │   └── Main.hs
    └── stack.yaml
    

    array.c: define an array in a C file, for example:

    int array[2][3] =  
        {{1, 24, 1},
         {2, 19, 1}};
    

    helloffi.c: define a function that uses this array, for example:

    #include "helloffi.h"
    
    int getCoef(unsigned i, unsigned j){
        return array[i][j];
    }
    

    helloffi.h, the header file:

    int array[2][3];
    int getCoef(unsigned, unsigned);
    

    That's all for the C part. Now the Haskell part. Make a library module importing the C function.

    Lib.hs:

    {-# LANGUAGE ForeignFunctionInterface #-}
    module Lib
      where
    import           Foreign.C.Types       
    
    foreign import ccall "getCoef" c_getCoef
        :: CUInt -> CUInt -> IO CInt
    

    Main.hs, to be compiled to an executable:

    module Main
      where
    import           Lib
    
    main :: IO ()
    main = do
        x <- c_getCoef 0 1
        print x
    

    That's all. And now, the mystery. Compile the library (to get the module Lib and the executable generated from Main.hs, let's say this one is called test).

    stack exec ghci, gives the correct result (24):

    Prelude> :l src/Main.hs 
    [1 of 1] Compiling Main             ( src/Main.hs, interpreted )
    Ok, one module loaded.
    *Main> main
    24
    

    run the executable, gives a wrong result (always 0):

    $ .stack-work/install/x86_64-linux/lts-11.4/8.2.2/bin/test 
    0
    

    The test executable is the compiled Main.hs. However it does not correctly read the entries of the array in array.c, while :l src/Main.hs after stack exec ghci gives the correct result.

    Isn't it weird ? Does anyone has an explanation ?

    Solution

    I don't know yet why the behavior differs between stack exec ghci and the executable but now one has a solution thanks to @Alec's comments below: it suffices to replace int array[2][3] in the header file with extern int array[2][3]. It looks like the executable considers int array[2][3] as the definition of array, whose entries are initialized to 0, while stack exec ghci considers it as the declaration of array.