2012-05-18 5 views
51

Ho un problema riguardante l'FFI in Haskell e la modalità interattiva di GHC again.Problema di collegamento del runtime GHCi durante l'uso delle dichiarazioni FFI

consideri 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" 

e un 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 [email protected] 

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

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

lo trovi anche here as a gist.

Quindi, il mio problema ora:

$ 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, che cosa è sbagliato? È interessante notare che ottengo un errore diverso su i686 (sopra, si tratta di un sistema di x86_64, ma entrambi 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. 

Inoltre, c'è qualche documentazione a riguardo? Mi sento come se fossi l'unico ad avere momenti difficili con FFI e GHCi là fuori.

edit: nota, che make test funziona bene:

$ 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 
+0

È possibile entrare in situazioni se si tenta di collegare staticamente un modulo a un simbolo FFI; e anche caricarlo dinamicamente. –

+0

puoi elaborare? o come si può risolvere questo? –

+3

Ho giocato un po 'con esso e sembra essere un bug in GHCi. Il simbolo viene esaminato due volte: una volta perché viene caricato sulla riga di comando tramite il file .o e una volta perché viene caricato il file .hs. Sembra. Forse non dovrebbe collegarsi affatto all'avvio di ghci, ma solo quando si eseguono cose? –

risposta

3

Questo è a known limitation di file oggetto il collegamento dinamico a livello di interprete bytecode, GHCi.

Se si carica il codice compilato collegato staticamente a un determinato oggetto C e quindi si interpreta anche Haskell al volo che fa riferimento anche tramite l'FFI allo stesso oggetto C, il linker di runtime verrà forzato a caricare il C oggetto dinamicamente.

Ora avete due versioni del simbolo C nello spazio degli indirizzi e ne derivano i guasti.

È necessario interpretare tutto in modalità GHCi oppure abbandonare l'utilizzo di GHCi per questo processo. Per alcuni linker del sistema operativo, è possibile esporre la tabella dei simboli collegata staticamente tramite la tabella dinamica (il flag -x).

+0

[Ecco l'altra tua risposta a una domanda simile ] (http://stackoverflow.com/a/13398390/439034). Bella risposta Sebbene non riesca a capire quale impostazione comporterebbe il flag '-x' quando si lavora con GHC api e' dynCompileExpr'. Sto indovinando un certo valore per 'ghcLink' (in chiamata a' setSessionDynFlags') potrebbe farlo, ma finora nessuna fortuna. Forse la bandiera deve essere impostata per la sessione "genitore". – worldsayshi