50
votes

I have a problem regarding FFI in Haskell and the interactive mode of GHC again.

Consider FFISo.hs:

{-# LANGUAGE OverloadedStrings #-}
module Main where

import qualified Data.ByteString.Char8 as B

import FFIFun.Foo

main :: IO ()
main = do
  B.putStrLn "main"
  callMeFromC
  callMeFromHaskell
  return ()

c.c:

#include <stdio.h>

void callMeFromC(void);

void callMeFromHaskell(void)
{
    printf("callMeFromHaskell\n");
    callMeFromC();
}

FFIFun/Foo.hs:

{-# LANGUAGE OverloadedStrings #-}
{-# LANGUAGE ForeignFunctionInterface #-}
module FFIFun.Foo where

import qualified Data.ByteString.Char8 as B

foreign import ccall "callMeFromHaskell"
  callMeFromHaskell :: IO ()

foreign export ccall callMeFromC :: IO ()
callMeFromC :: IO ()
callMeFromC = B.putStrLn "callMeFromC"

and a Makefile:

SHELL := bash

GHC_OPT := -Wall -O2 -fno-warn-unused-do-bind


all: ffiso

test: ffiso
    ./$<

ffiso: FFISo.hs c.c
    ghc --make $(GHC_OPT) $^ -o $@

clean:
    rm -rf *{.hi,o,_stub.*} ffiso FFIFun/*{.hi,.o,_stub.*}

ghci: ffiso
    ghci -package bytestring FFIFun/Foo.o c.o FFISo.hs

you find it also here as a gist.

So, my problem now:

$ make ghci
[...]
Ok, modules loaded: Main, FFIFun.Foo.
Prelude Main> -- fine, it's loading.
Prelude Main> :t callMeFromC

<interactive>:1:1: Not in scope: `callMeFromC'
Prelude Main> -- uhm, why?
Prelude Main> :t main
main :: IO ()
Prelude Main> main


GHCi runtime linker: fatal error: I found a duplicate definition for symbol
   FFIFunziFoo_callMeFromC_info
whilst processing object file
   ./FFIFun/Foo.o
This could be caused by:
   * Loading two different object files which export the same symbol
   * Specifying the same object file twice on the GHCi command line
   * An incorrect `package.conf' entry, causing some object to be
     loaded twice.
GHCi cannot safely continue in this situation.  Exiting now.  Sorry.

Hrmpf, what is wrong here? Interestingly I get an different error on i686 (above, it's a x86_64 system, but both GHC 7.4.1):

GHCi runtime linker: fatal error: I found a duplicate definition for symbol
   __stginit_FFIFunziFoo
whilst processing object file
   ./FFIFun/Foo.o
This could be caused by:
   * Loading two different object files which export the same symbol
   * Specifying the same object file twice on the GHCi command line
   * An incorrect `package.conf' entry, causing some object to be
     loaded twice.
GHCi cannot safely continue in this situation.  Exiting now.  Sorry.

Also, is there some documentation about it? I feel like I'm the only one who has hard times with FFI and GHCi out there.

edit: note, that make test works fine:

$ ghc --make -Wall -O2 -fno-warn-unused-do-bind FFISo.hs c.c -o ffiso
[1 of 2] Compiling FFIFun.Foo       ( FFIFun/Foo.hs, FFIFun/Foo.o )
[2 of 2] Compiling Main             ( FFISo.hs, FFISo.o )
Linking ffiso ...
./ffiso
main
callMeFromC
callMeFromHaskell
callMeFromC
1
You can get into situations if you try to both statically link a module against an FFI symbol; and also dynamically load it.Don Stewart
can you elaborate? or how can one resolve this?h_s
I played around with it a bit and it seems to be a bug in GHCi. The symbol is looked at twice: Once because it is loaded on the command line via the .o file, and once because the .hs file is loaded. It seems. Maybe it should not link at all when starting ghci, but only when executing stuff?Joachim Breitner
thanks for your comment. meanwhile I upgraded from 7.4.1 to 7.4.2 and get a different errormessage now, I don't even get a prompt on x86_64 (but on x86 I do). sigh. strangely enough I fixed the problem in my project (wien.tomnetworks.com/gitweb/?p=mate.git;a=summary x86 only, see the makefile), but I'm not able to fix it in the gist above. it's really weird, probably I should report a GHC bug or something.lewurm

1 Answers

3
votes

This is a known limitation of dynamic linking object files in the bytecode interpreter, GHCi.

If you load compiled code that was statically linked against a given C object, and then also interpret some Haskell on the fly that also refers via the FFI to the same C object, the runtime linker will be forced to load the C object dynamically.

Now you have two versions of the C symbol in your address space, and failures ensue.

You must either interpret everything under GHCi mode, or abandon using GHCi for this process. For some OS linkers, you can expose the statically linked symbol table via the dynamic table, (the -x flag).