我在 Ubuntu 10.04 中使用 GHC 6.12.1
当我尝试使用 FFI 语法进行静态存储时,只有以解释模式(即 GHCI)运行的模块才能正常工作。编译的模块有无效的指针,并且不工作。我想知道是否有人可以重现该问题,这是否是我的代码或 GHC 中的错误,以及(如果是后者)是否是已知问题。
我正在使用sys_siglist
它,因为它存在于我系统上的标准库中,但我不相信实际使用的存储很重要(我在编写与 libidn 的绑定时发现了这一点)。如果有帮助,sys_siglist
定义<signal.h>
为:
extern __const char *__const sys_siglist[_NSIG];
我认为这种类型可能是问题所在,所以我也尝试将它包装在一个普通的 C 过程中:
#include<stdio.h>
const char **test_ffi_import()
{
printf("C think sys_siglist = %X\n", sys_siglist);
return sys_siglist;
}
但是,导入不会改变结果,并且printf()
调用会打印与show siglist_a
.
我怀疑这与静态和动态库加载有关。
更新:#haskell 中有人建议这可能是 64 位特定的;如果有人试图复制它,您能否在评论中提及您的架构以及它是否有效?
代码如下:
-- A.hs
{-# LANGUAGE ForeignFunctionInterface #-}
module A where
import Foreign
import Foreign.C
foreign import ccall "&sys_siglist"
siglist_a :: Ptr CString
--
-- B.hs
{-# LANGUAGE ForeignFunctionInterface #-}
module B where
import Foreign
import Foreign.C
foreign import ccall "&sys_siglist"
siglist_b :: Ptr CString
--
-- Main.hs
{-# LANGUAGE ForeignFunctionInterface #-}
module Main where
import Foreign
import Foreign.C
import A
import B
foreign import ccall "&sys_siglist"
siglist_main :: Ptr CString
main = do
putStrLn $ "siglist_a = " ++ show siglist_a
putStrLn $ "siglist_b = " ++ show siglist_b
putStrLn $ "siglist_main = " ++ show siglist_main
peekSiglist "a " siglist_a
peekSiglist "b " siglist_b
peekSiglist "main" siglist_main
peekSiglist name siglist = do
ptr <- peekElemOff siglist 2
str <- maybePeek peekCString ptr
putStrLn $ "siglist_" ++ name ++ "[2] = " ++ show str
我希望得到类似这样的输出,其中所有指针值都相同且有效:
$ runhaskell Main.hs
siglist_a = 0x00007f53a948fe00
siglist_b = 0x00007f53a948fe00
siglist_main = 0x00007f53a948fe00
siglist_a [2] = Just "Interrupt"
siglist_b [2] = Just "Interrupt"
siglist_main[2] = Just "Interrupt"
但是,如果我编译 A.hs(带有ghc -c A.hs
),则输出将更改为:
$ runhaskell Main.hs
siglist_a = 0x0000000040378918
siglist_b = 0x00007fe7c029ce00
siglist_main = 0x00007fe7c029ce00
siglist_a [2] = Nothing
siglist_b [2] = Just "Interrupt"
siglist_main[2] = Just "Interrupt"