gpt4 book ai didi

haskell - GHCi 不适用于 FFI 导出声明/共享库

转载 作者:行者123 更新时间:2023-12-04 11:12:24 26 4
gpt4 key购买 nike

我对 Haskell 中的 FFI 和 GHC 的交互模式有疑问。

(来源也可通过 gist 获得):

FFISo.hs:

{-# LANGUAGE OverloadedStrings #-}
{-# LANGUAGE ForeignFunctionInterface #-}
module Main 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"

main :: IO ()
main = do
B.putStrLn "main"
callMeFromHaskell
return ()

抄送:
#include <stdio.h>

void callMeFromC(void);

void callMeFromHaskell(void)
{
printf("callMeFromHaskell\n");
callMeFromC();
}

生成文件:
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 ffiso *_stub.*

ghci0: ffiso
echo main | ghci FFISo.hs

ghci1: ffiso
echo main | ghci FFISo.hs c.o

ghci2: ffiso
echo main | ghci FFISo.hs c.o FFISo.o

编译和链接工作正常:
$ make test
ghc --make -Wall -O2 -fno-warn-unused-do-bind FFISo.hs c.c -o ffiso
[1 of 1] Compiling Main ( FFISo.hs, FFISo.o )
Linking ffiso ...
./ffiso
main
callMeFromHaskell
callMeFromC

但是,如果我想使用 GHCi,它会失败并显示以下消息:
$ make ghci0
echo main | ghci FFISo.hs
GHCi, version 7.4.1: http://www.haskell.org/ghc/ :? for help
Loading package ghc-prim ... linking ... done.
Loading package integer-gmp ... linking ... done.
Loading package base ... linking ... done.
Ok, modules loaded: Main.
Prelude Main> Loading package bytestring-0.9.2.1 ... linking ... done.
<interactive>: FFISo.o: unknown symbol `callMeFromHaskell'

Prelude Main> Leaving GHCi.

好吧,让我们尝试给 GHCi c.o目标文件。
$ make ghci1
echo main | ghci FFISo.hs c.o
GHCi, version 7.4.1: http://www.haskell.org/ghc/ :? for help
Loading package ghc-prim ... linking ... done.
Loading package integer-gmp ... linking ... done.
Loading package base ... linking ... done.
Loading object (static) c.o ... done
ghc: c.o: unknown symbol `callMeFromC'
linking extra libraries/objects failed
make: *** [ghci1] Error 1
final link ...

哦,好吧...让我们尝试使用 FFISo.o:
$ make ghci2
echo main | ghci FFISo.hs c.o FFISo.o
GHCi, version 7.4.1: http://www.haskell.org/ghc/ :? for help
Loading package ghc-prim ... linking ... done.
Loading package integer-gmp ... linking ... done.
Loading package base ... linking ... done.
Loading object (static) c.o ... done
Loading object (static) FFISo.o ... done
ghc: FFISo.o: unknown symbol `bytestringzm0zi9zi2zi1_DataziByteStringziInternal_PS_con_info'
linking extra libraries/objects failed
make: *** [ghci2] Error 1
final link ...

这就是我卡住的地方。

我用两种不同的环境对其进行了测试,结果相同:
$ # system 1
$ ghc --version
The Glorious Glasgow Haskell Compilation System, version 7.4.1
$ uname -a
Linux phenom 3.2.13-1-ARCH #1 SMP PREEMPT Sat Mar 24 09:10:39 CET 2012 x86_64 AMD Phenom(tm) II X6 1055T Processor AuthenticAMD GNU/Linux

$ # system 2
$ ghc --version
The Glorious Glasgow Haskell Compilation System, version 6.12.1
$ uname -a
Linux hermann 2.6.32-22-generic-pae #36-Ubuntu SMP Thu Jun 3 23:14:23 UTC 2010 i686 GNU/Linux

最佳答案

调用 GHCi 时需要指定更多要链接的对象,因为 C 对象 c.o在链接顺序方面特别挑剔。

首先,您需要添加 bytestring包的目标文件。这是通过添加 -package bytestring 来完成的。到 GHCi 命令行。

然后,您需要添加定义 callMeFromC 的实际目标文件。 .当FFISo.hs已编译,它不会生成导出 callMeFromC 的目标文件.它改为使用 GHC 命名约定并导出 Main_zdfcallMeFromCzuak4_closure ,它实际上是一个静态全局变量,指向包含实际函数定义和环境的闭包/“thunk”。这样你就不能写这样的东西:

foregin export ccall foo :: IO ()
foo = undefined

...并在程序启动后立即崩溃,因为 foo 的“函数值”无法评价。仅在实际使用该函数时才检查该函数定义。

GHC 生成一个 stub 文件,其中包含用于从 C 调用 Haskell 函数的 C 代码。此文件称为 FFISo_stub.c , 并编译成 FFISo_stub.o为你。此目标文件导出 callMeFromC 的“C 版本”。可以直接调用。随意检查生成的代码,这很有趣。

总而言之,调用 GHCi 时需要使用这个命令行:
ghci -package bytestring FFISo.o c.o FFISo_stub.o FFISo.hs

关于haskell - GHCi 不适用于 FFI 导出声明/共享库,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/10123040/

26 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com