Reputation: 6091
I want to create a haskell interpreter that I can use from C++ on linux.
I have a file FFIInterpreter.hs which implements the interpreter in haskell and exports the functions via FFI to C++.
module FFIInterpreter where
import Language.Haskell.Interpreter
import Data.IORef
import Foreign.StablePtr
import Foreign.C.Types
import Foreign.C.String
import Control.Monad
import Foreign.Marshal.Alloc
type Session = Interpreter ()
type Context = StablePtr (IORef Session)
foreign export ccall createContext :: CString -> IO Context
createContext :: CString -> IO Context
createContext name = join ((liftM doCreateContext) (peekCString name))
where
doCreateContext :: ModuleName -> IO Context
doCreateContext name
= do let session = newModule name
_ <- runInterpreter session
liftIO $ newStablePtr =<< newIORef session
newModule :: ModuleName -> Session
newModule name = loadModules [name] >> setTopLevelModules [name]
foreign export ccall freeContext :: Context -> IO ()
freeContext :: Context -> IO ()
freeContext = freeStablePtr
foreign export ccall runExpr :: Context -> CString -> IO CString
runExpr :: Context -> CString -> IO CString
runExpr env input = join ((liftM newCString) (join (((liftM liftM) doRunExpr) env (peekCString input))))
where
doRunExpr :: Context -> String -> IO String
doRunExpr env input
= do env_value <- deRefStablePtr env
tcs_value <- readIORef env_value
result <- runInterpreter (tcs_value >> eval input)
return $ either show id result
foreign export ccall freeString :: CString -> IO ()
freeString :: CString -> IO ()
freeString = Foreign.Marshal.Alloc.free
When I compile the whole project with ghc, everything works fine. I use the following command:
ghc -no-hs-main FFIInterpreter.hs main.cpp -lstdc++
But the haskell module is only a small piece of the C++ project and I don't want the whole project to depend on ghc.
So I want to build a dynamic library with ghc and then link it to the project using g++.
$ ghc -shared -fPIC FFIInterpreter.hs module_init.c -lstdc++
[1 of 1] Compiling FFIInterpreter ( FFIInterpreter.hs, FFIInterpreter.o )
Linking a.out ...
/usr/bin/ld: /usr/lib/haskell-packages/ghc/lib/hint-0.3.3.2/ghc-7.0.3/libHShint-0.3.3.2.a(Interpreter.o): relocation R_X86_64_32S against `.data' can not be used when making a shared object; recompile with -fPIC
/usr/lib/haskell-packages/ghc/lib/hint-0.3.3.2/ghc-7.0.3/libHShint-0.3.3.2.a: could not read symbols: Bad value
collect2: ld gab 1 als Ende-Status zurück
So I added the -dynamic keyword, but that also doesn't work:
$ ghc -dynamic -shared -fPIC FFIInterpreter.hs librarymain.cpp -lstdc++
FFIInterpreter.hs:3:8:
Could not find module `Language.Haskell.Interpreter':
Perhaps you haven't installed the "dyn" libraries for package `hint-0.3.3.2'?
Use -v to see a list of the files searched for.
I searched my system for Interpreter.dyn_hi but didn't find it. Is there a way to get it? I also tried to install hint manually, but this also doesn't deliver the Interpreter.dyn_hi file.
Upvotes: 3
Views: 1083
Reputation: 183978
You have to install the library (and all it depends on) with the --enable-shared
flag (using cabal-install) to get the .dyn_hi
and .dyn_o
files. You may consider setting that option in your ~/.cabal/config
file.
Perhaps the easiest way is to uncomment the shared: XXX
line in ~/.cabal/config
, set the option to True
and
cabal install --reinstall world
For safety, run that with the --dry-run
option first to detect problems early. If the --dry-run
output looks reasonable, go ahead and reinstall - it will take a while, though.
Upvotes: 3