如何使用 Haskell 中的 FunPtr?
How do I use a FunPtr from Haskell?
假设有以下文件:
test2.h:
typedef int (*signature) ();
extern const signature lol2;
test2.c:
#include "test2.h"
int lol() {
return 42;
}
const signature lol2 = lol;
Test2.hs:
module Main where
import Foreign.C
import Foreign.Ptr
type Fun =
IO CInt
foreign import ccall
"test2.h lol2"
fun_ptr
:: FunPtr Fun
foreign import ccall "dynamic" mkFun :: FunPtr Fun -> Fun
lol = mkFun fun_ptr
main = do
fortytwo <- lol
putStrLn $ show $ fortytwo
编译如下:
gcc -shared test2.c -Wall -Wextra -o libtest2.so -g3 -ggdb3
ghc -o test2 Test2.hs -ltest2 -optl-Wl,-rpath,. -L. -g
(GHC 在 lol2 声明之前发出关于缺少“&”的警告,但我认为警告是错误的,所以我忽略了它。另外,请注意我没有使用 -dynamic
。如果我做,结果是一样的)
但是,我得到一个 SIGSEGV 而 运行:
(gdb) break scheduleWaitThread
Breakpoint 1 at 0x468150: file rts/Schedule.c, line 2509.
(gdb) r
Starting program: [...]/test2
[Thread debugging using libthread_db enabled]
Using host libthread_db library "/lib/x86_64-linux-gnu/libthread_db.so.1".
Breakpoint 1, scheduleWaitThread (tso=0x4200105388, ret=ret@entry=0x0, pcap=pcap@entry=0x7fffffffd7f8) at rts/Schedule.c:2509
2509 rts/Schedule.c: No such file or directory.
(gdb) bt
#0 scheduleWaitThread (tso=0x4200105388, ret=ret@entry=0x0, pcap=pcap@entry=0x7fffffffd7f8) at rts/Schedule.c:2509
#1 0x0000000000483864 in rts_evalLazyIO (cap=cap@entry=0x7fffffffd7f8, p=p@entry=0x4a5420, ret=ret@entry=0x0) at rts/RtsAPI.c:530
#2 0x00000000004707ae in hs_main (argc=1, argv=0x7fffffffd9e8, main_closure=0x4a5420, rts_config=...) at rts/RtsMain.c:72
#3 0x0000000000406b46 in main ()
(gdb) finish
Run till exit from #0 scheduleWaitThread (tso=0x4200105388, ret=ret@entry=0x0, pcap=pcap@entry=0x7fffffffd7f8) at rts/Schedule.c:2509
Program received signal SIGSEGV, Segmentation fault.
0x00000000004a4d90 in lol2 ()
(gdb)
崩溃后堆栈似乎无法使用:
(gdb) bt
#0 0x00000000004a4d90 in lol2 ()
#1 0x000000000040669d in r2ad_info ()
#2 0x0000000000000000 in ?? ()
我做错了什么?我该如何调试?
ccall
只能导入函数,而lol2
是没有函数的。使用具有 value
资格的 capi
导入:
{-# LANGUAGE CApiFFI #-}
module Main where
-- ... etc ...
foreign import capi "test2.h value lol2" fun_ptr :: FunPtr Fun
-- ... etc ...
它不是很明显,但是 the manual says to do this,它确实有效。您看到的警告信息仍然出现;我想你可能想将其作为错误报告。
假设有以下文件:
test2.h:
typedef int (*signature) ();
extern const signature lol2;
test2.c:
#include "test2.h"
int lol() {
return 42;
}
const signature lol2 = lol;
Test2.hs:
module Main where
import Foreign.C
import Foreign.Ptr
type Fun =
IO CInt
foreign import ccall
"test2.h lol2"
fun_ptr
:: FunPtr Fun
foreign import ccall "dynamic" mkFun :: FunPtr Fun -> Fun
lol = mkFun fun_ptr
main = do
fortytwo <- lol
putStrLn $ show $ fortytwo
编译如下:
gcc -shared test2.c -Wall -Wextra -o libtest2.so -g3 -ggdb3
ghc -o test2 Test2.hs -ltest2 -optl-Wl,-rpath,. -L. -g
(GHC 在 lol2 声明之前发出关于缺少“&”的警告,但我认为警告是错误的,所以我忽略了它。另外,请注意我没有使用 -dynamic
。如果我做,结果是一样的)
但是,我得到一个 SIGSEGV 而 运行:
(gdb) break scheduleWaitThread
Breakpoint 1 at 0x468150: file rts/Schedule.c, line 2509.
(gdb) r
Starting program: [...]/test2
[Thread debugging using libthread_db enabled]
Using host libthread_db library "/lib/x86_64-linux-gnu/libthread_db.so.1".
Breakpoint 1, scheduleWaitThread (tso=0x4200105388, ret=ret@entry=0x0, pcap=pcap@entry=0x7fffffffd7f8) at rts/Schedule.c:2509
2509 rts/Schedule.c: No such file or directory.
(gdb) bt
#0 scheduleWaitThread (tso=0x4200105388, ret=ret@entry=0x0, pcap=pcap@entry=0x7fffffffd7f8) at rts/Schedule.c:2509
#1 0x0000000000483864 in rts_evalLazyIO (cap=cap@entry=0x7fffffffd7f8, p=p@entry=0x4a5420, ret=ret@entry=0x0) at rts/RtsAPI.c:530
#2 0x00000000004707ae in hs_main (argc=1, argv=0x7fffffffd9e8, main_closure=0x4a5420, rts_config=...) at rts/RtsMain.c:72
#3 0x0000000000406b46 in main ()
(gdb) finish
Run till exit from #0 scheduleWaitThread (tso=0x4200105388, ret=ret@entry=0x0, pcap=pcap@entry=0x7fffffffd7f8) at rts/Schedule.c:2509
Program received signal SIGSEGV, Segmentation fault.
0x00000000004a4d90 in lol2 ()
(gdb)
崩溃后堆栈似乎无法使用:
(gdb) bt
#0 0x00000000004a4d90 in lol2 ()
#1 0x000000000040669d in r2ad_info ()
#2 0x0000000000000000 in ?? ()
我做错了什么?我该如何调试?
ccall
只能导入函数,而lol2
是没有函数的。使用具有 value
资格的 capi
导入:
{-# LANGUAGE CApiFFI #-}
module Main where
-- ... etc ...
foreign import capi "test2.h value lol2" fun_ptr :: FunPtr Fun
-- ... etc ...
它不是很明显,但是 the manual says to do this,它确实有效。您看到的警告信息仍然出现;我想你可能想将其作为错误报告。