Haskell 与 c 的接口
我一直在想用 haskell 创建 midori 插件会很好,但这似乎几乎是不可能的。问题在于通过 ffi 导出 haskell 函数,因为 ghc 编译器使用了大量的 -u 开关。
有谁见过 haskell 在类似的上下文中使用,而不必用 ghc 替换 gcc 吗?如果是这样,结果如何?他们经历了哪些困难?
编辑:需要一些示例,所以这里:
export.hs
{-# LANGUAGE ForeignFunctionInterface #-}
module Export where
import Foreign.C
import Foreign.C.Types
foo :: IO Int
foo = return 2
foreign export ccall foo :: IO Int
test.c(ifdefs snipped)
#include <stdio.h>
#include "HsFFI.h"
#include "export_stub.h"
extern void __stginit_Export(void);
int main(int argc, char **argv)
{
int i;
hs_init(&argc, &argv);
hs_add_root(__stginit_Export);
i = foo();
printf("%d\n", i);
hs_exit();
return 0;
}
使用 ghc --make -no-hs-main export.hs test.c 编译创建一个 a.out 可以运行的可执行文件。 ghc 使用以下命令进行链接:
collect2 --build-id --eh-frame-hdr -m elf_i386 --hash-style=both -dynamic-linker /lib/ld-linux.so.2 - o a.out -z relro -u ghczmprim_GHCziTypes_Izh_static_info -u ghczmprim_GHCziTypes_Czh_static_info -u ghczmprim_GHCziTypes_Fzh_static_info -u ghczmprim_GHCziTypes_Dzh_static_info -u base_GHCziPtr_Ptr_static_info -u base_GHCziWord_Wzh_static_信息 -u base_GHCziInt_I8zh_static_info -u base_GHCziInt_I16zh_static_info -u base_GHCziInt_I32zh_static_info -u base_GHCziInt_I64zh_static_info -u base_GHCziWord_W8zh_static_info -u base_GHCziWord_W16zh_static_info -u base_GHCziWord_W32zh_static_info -u base_GHCziWord_W64zh_static_info - u base_GHCziStable_StablePtr_static_info -u ghczmprim_GHCziTypes_Izh_con_info -u ghczmprim_GHCziTypes_Czh_con_info -u ghczmprim_GHCziTypes_Fzh_con_info -u ghczmprim_GHCziTypes_Dzh_con_info -u base_GHCziPtr_Ptr_con_info -u base_GHC ziPtr_FunPtr_con_info -u base_GHCziStable_StablePtr_con_info -u ghczmprim_GHCziBool_False_closure -u ghczmprim_GHCziBool_True_closure -u base_GHCziPack_unpackCString_closure -u base_GHCziIOziException_stackOverflow_closure -u base_GHCziIOziException_heapOverflow_closure -u base_ControlziExceptionziBase_ nonTermination_closure -u base_GHCziIOziException_blockedIndefinitelyOnMVar_closure -u base_GHCziIOziException_blockedIndefinitelyOnSTM_closure -u base_ControlziExceptionziBase_nestedAtomically_closure -ubase_GHCziWeak_runFinalizzerBatch_closure -ubase_GHCziTopHandler_runIO_closure -ubase_GHCziTopHandler_runNonIO_closure -ubase_GHCziConc_ensureIOManagerIsRunning_closure -ubase_GHCziConc_runSparks_closure -ubase_GHCziConc_runHandlers_closure /usr/lib/gcc/i486-linux-gnu/4.4.3/ ../../../../lib/crt1 .o /usr/lib/gcc/i486-linux-gnu/4.4.3/../../../../lib/crti.o /usr/lib/gcc/i486-linux-gnu/4.4 .3/crtbegin.o -L/usr/lib/ghc-6.12.1/base-4.2.0.0 -L/usr/lib/ghc-6.12.1/integer-gmp-0.2.0.0 -L/usr/lib /ghc-6.12.1/ghc-prim-0.2.0.0 -L/usr/lib/ghc-6.12.1 -L/usr/lib/gcc/i486-linux-gnu/4.4.3 -L/usr/lib /gcc/i486-linux-gnu/4.4.3 -L/usr/lib/gcc/i486-linux-gnu/4.4.3/../../../../lib -L/lib/. ./lib -L/usr/lib/../lib -L/usr/lib/gcc/i486-linux-gnu/4.4.3/../../.. -L/usr/lib/i486- linux-gnu 导出.o 导出存根.o 测试.o -lHSbase-4.2.0.0 -lHSinteger-gmp-0.2.0.0 -lgmp -lHSghc-prim-0.2.0.0 -lHSrts -lm -lffi -lrt -ldl -lgcc --根据需要 -lgcc_s --no-as-needed -lc -lgcc --as-needed -lgcc_s --no-as-needed /usr/lib/gcc/i486-linux-gnu/4.4.3/crtend.o /usr/lib/gcc/i486-linux-gnu/4.4.3/../../../../lib/crtn.o
删除 -u
开关(只留下 -l、-L 和一些额外的标志) 前面的命令不会编译并返回(大约 50 个左右) 线)
/usr/lib/ghc-6.12.1/libHSrts.a(RtsAPI.o): In function `rts_mkFunPtr':
(.text+0x5a9): undefined reference to `base_GHCziPtr_FunPtr_con_info'
/usr/lib/ghc-6.12.1/libHSrts.a(RtsAPI.o): In function `rts_mkString':
(.text+0x60f): undefined reference to `base_GHCziPack_unpackCString_closure'
I've been thinking that it would be nice to create midori plugins with haskell, but it seems to be nigh impossible. The problem lies with exporting haskell functions through ffi, as the ghc compiler makes use of a massive amount of -u switches.
tHas anyone seen haskell been used in a similar context, without having to replace gcc for ghc? If so, how did it work out and what hoops did they go through?
Edit: Some examples were requested, so here:
export.hs
{-# LANGUAGE ForeignFunctionInterface #-}
module Export where
import Foreign.C
import Foreign.C.Types
foo :: IO Int
foo = return 2
foreign export ccall foo :: IO Int
test.c (ifdefs snipped)
#include <stdio.h>
#include "HsFFI.h"
#include "export_stub.h"
extern void __stginit_Export(void);
int main(int argc, char **argv)
{
int i;
hs_init(&argc, &argv);
hs_add_root(__stginit_Export);
i = foo();
printf("%d\n", i);
hs_exit();
return 0;
}
Compiling with ghc --make -no-hs-main export.hs test.c
creates an a.out
executable which works. The ghc uses the following command for linking:
collect2 --build-id --eh-frame-hdr -m elf_i386 --hash-style=both -dynamic-linker /lib/ld-linux.so.2 -o a.out -z relro -u ghczmprim_GHCziTypes_Izh_static_info -u ghczmprim_GHCziTypes_Czh_static_info -u ghczmprim_GHCziTypes_Fzh_static_info -u ghczmprim_GHCziTypes_Dzh_static_info -u base_GHCziPtr_Ptr_static_info -u base_GHCziWord_Wzh_static_info -u base_GHCziInt_I8zh_static_info -u base_GHCziInt_I16zh_static_info -u base_GHCziInt_I32zh_static_info -u base_GHCziInt_I64zh_static_info -u base_GHCziWord_W8zh_static_info -u base_GHCziWord_W16zh_static_info -u base_GHCziWord_W32zh_static_info -u base_GHCziWord_W64zh_static_info -u base_GHCziStable_StablePtr_static_info -u ghczmprim_GHCziTypes_Izh_con_info -u ghczmprim_GHCziTypes_Czh_con_info -u ghczmprim_GHCziTypes_Fzh_con_info -u ghczmprim_GHCziTypes_Dzh_con_info -u base_GHCziPtr_Ptr_con_info -u base_GHCziPtr_FunPtr_con_info -u base_GHCziStable_StablePtr_con_info -u ghczmprim_GHCziBool_False_closure -u ghczmprim_GHCziBool_True_closure -u base_GHCziPack_unpackCString_closure -u base_GHCziIOziException_stackOverflow_closure -u base_GHCziIOziException_heapOverflow_closure -u base_ControlziExceptionziBase_nonTermination_closure -u base_GHCziIOziException_blockedIndefinitelyOnMVar_closure -u base_GHCziIOziException_blockedIndefinitelyOnSTM_closure -u base_ControlziExceptionziBase_nestedAtomically_closure -u base_GHCziWeak_runFinalizzerBatch_closure -u base_GHCziTopHandler_runIO_closure -u base_GHCziTopHandler_runNonIO_closure -u base_GHCziConc_ensureIOManagerIsRunning_closure -u base_GHCziConc_runSparks_closure -u base_GHCziConc_runHandlers_closure /usr/lib/gcc/i486-linux-gnu/4.4.3/../../../../lib/crt1.o /usr/lib/gcc/i486-linux-gnu/4.4.3/../../../../lib/crti.o /usr/lib/gcc/i486-linux-gnu/4.4.3/crtbegin.o -L/usr/lib/ghc-6.12.1/base-4.2.0.0 -L/usr/lib/ghc-6.12.1/integer-gmp-0.2.0.0 -L/usr/lib/ghc-6.12.1/ghc-prim-0.2.0.0 -L/usr/lib/ghc-6.12.1 -L/usr/lib/gcc/i486-linux-gnu/4.4.3 -L/usr/lib/gcc/i486-linux-gnu/4.4.3 -L/usr/lib/gcc/i486-linux-gnu/4.4.3/../../../../lib -L/lib/../lib -L/usr/lib/../lib -L/usr/lib/gcc/i486-linux-gnu/4.4.3/../../.. -L/usr/lib/i486-linux-gnu export.o export_stub.o test.o -lHSbase-4.2.0.0 -lHSinteger-gmp-0.2.0.0 -lgmp -lHSghc-prim-0.2.0.0 -lHSrts -lm -lffi -lrt -ldl -lgcc --as-needed -lgcc_s --no-as-needed -lc -lgcc --as-needed -lgcc_s --no-as-needed /usr/lib/gcc/i486-linux-gnu/4.4.3/crtend.o /usr/lib/gcc/i486-linux-gnu/4.4.3/../../../../lib/crtn.o
Removing the -u
switches (leaving just -l, -L and some extra flags) from
the previous command doesn't compile and returns (and some 50 or so more
lines)
/usr/lib/ghc-6.12.1/libHSrts.a(RtsAPI.o): In function `rts_mkFunPtr':
(.text+0x5a9): undefined reference to `base_GHCziPtr_FunPtr_con_info'
/usr/lib/ghc-6.12.1/libHSrts.a(RtsAPI.o): In function `rts_mkString':
(.text+0x60f): undefined reference to `base_GHCziPack_unpackCString_closure'
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(2)
我能够解决这个问题。
我正在使用以下文件:
main.c
lib.hs
module_init.c
我正在使用 ghc --make -shared -dynamic -fPIC -o 编译库
libtest.so lib.hs module_init.c -lHSrts-ghc6.12.1
-optl-Wl,-rpath,/usr/lib/ghc-6.12.1/ -L/usr/lib/ghc-6.12.1 和
可执行文件 gcc -c main.c -I/usr/lib/ghc-6.12.1/include -L。 -l测试
-Wl,-rpath=$PWD
重要的部分是使库共享并拥有 rts 库
链接也不是默认的。 rpath 使得它可以
在没有 LD_LIBRARY_PATH 的情况下运行。
http://weblog.haskell.cz/pivnik/building- a-shared-library-in-haskell/
http://www.well-typed .com/blog/30
I was able to solve the problem.
I'm using the following files:
main.c
lib.hs
module_init.c
I'm compiling the library with
ghc --make -shared -dynamic -fPIC -o
and thelibtest.so lib.hs module_init.c -lHSrts-ghc6.12.1
-optl-Wl,-rpath,/usr/lib/ghc-6.12.1/ -L/usr/lib/ghc-6.12.1
executable with
gcc -c main.c -I/usr/lib/ghc-6.12.1/include -L. -ltest
-Wl,-rpath=$PWD
The important part is making the library shared and having the rts library
linked also which doesn't come default. The rpath makes it so that it can
be ran without LD_LIBRARY_PATH.
http://weblog.haskell.cz/pivnik/building-a-shared-library-in-haskell/
http://www.well-typed.com/blog/30
这可能是手册的相关部分:
8.2。将 FFI 与 GHC 结合使用
特别参见 8.2.1.2。您可以创建一个用 Haskell 编写并可从 C 代码调用的库。然后你只需要用 C 语言编写一些粘合代码即可将其变成插件或其他东西。不过我自己没有做过,请等待更有经验的
国外出口
用户来解答。This is probably the related part of the manual:
8.2. Using the FFI with GHC
See 8.2.1.2 in particular. You can make a library written in Haskell and callable from C code. Then you have only to write some glue code in C to turn in into a plugin or whatever. But I didn't do it myself, please wait for more experienced users of
foreign export
to answer.