我对Haskell中的FFI和GHC again的交互模式有疑问。
考虑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"
和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
你也发现它here as a gist。
所以,我现在的问题是:
$ 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,这里有什么问题?有趣的是,我在i686
上得到了一个不同的错误(上面,它是x86_64
系统,但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.
此外,是否有一些关于它的文件?我觉得我是唯一一个在FFI和GHCi遇到困难的人。
编辑:
请注意,make test
工作正常:
$ 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 :(得分:3)
这是字节码解释器GHCi中动态链接目标文件的a known limitation。
如果加载静态链接到给定C对象的已编译代码,然后同时解释一些Haskell,它也通过FFI引用到同一个C对象,则运行时链接程序将被强制加载C对象动态。
现在您的地址空间中有两个版本的C符号,随后出现故障。
您必须在GHCi模式下解释所有内容,或者放弃使用GHCi进行此过程。对于某些OS链接器,您可以通过动态表(-x
标志)公开静态链接的符号表。