Haskell 与 c 的接口

发布于 2024-10-07 08:05:11 字数 3681 浏览 4 评论 0原文

我一直在想用 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 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(2

任谁 2024-10-14 08:05:11

我能够解决这个问题。

我正在使用以下文件:

main.c

#include <stdio.h>
#include "lib_stub.h"
int main(int argc, char **argv)
{
    puts("foo");
    printf("%d\n", hsfun(5));
    return 0;
}

lib.hs

{-# LANGUAGE ForeignFunctionInterface #-}
module Test where
import Foreign.C.Types

hsfun :: CInt -> IO CInt
hsfun x = do
  putStrLn "Hello from haskell"
  return (42 * x)

foreign export ccall hsfun :: CInt -> IO CInt

module_init.c

#include <HsFFI.h>
extern void __stginit_Test(void);

static void library_init(void) __attribute__((constructor));
static void library_init(void)
{
    static char *argv[] = { "libtest.so", 0 }, **argv_ = argv;
    static int argc = 1;

    hs_init(&argc, &argv_);
    hs_add_root(__stginit_Test);
}

static void library_exit(void) __attribute__((destructor));
static void library_exit(void)
{
    hs_exit();
}

我正在使用 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

#include <stdio.h>
#include "lib_stub.h"
int main(int argc, char **argv)
{
    puts("foo");
    printf("%d\n", hsfun(5));
    return 0;
}

lib.hs

{-# LANGUAGE ForeignFunctionInterface #-}
module Test where
import Foreign.C.Types

hsfun :: CInt -> IO CInt
hsfun x = do
  putStrLn "Hello from haskell"
  return (42 * x)

foreign export ccall hsfun :: CInt -> IO CInt

module_init.c

#include <HsFFI.h>
extern void __stginit_Test(void);

static void library_init(void) __attribute__((constructor));
static void library_init(void)
{
    static char *argv[] = { "libtest.so", 0 }, **argv_ = argv;
    static int argc = 1;

    hs_init(&argc, &argv_);
    hs_add_root(__stginit_Test);
}

static void library_exit(void) __attribute__((destructor));
static void library_exit(void)
{
    hs_exit();
}

I'm compiling the library with 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
and the
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

过潦 2024-10-14 08:05:11

这可能是手册的相关部分:

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.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文