GHCi不适用于FFI导出声明/共享库 [英] GHCi doesn't work with FFI export declarations/shared libraries

查看:167
本文介绍了GHCi不适用于FFI导出声明/共享库的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我在Haskell的FFI和GHC的交互模式方面存在问题。
$ b (源代码也可以通过 gist ):

FFISo.hs:

  { - #LANGUAGE OverloadedStrings# - } 
{ - #LANGUAGE ForeignFunctionInterface# - }
模块Main其中

导入合格的Data.ByteString.Char8作为B

外部导入ccallcallMeFromHaskell
callMeFromHaskell :: IO()

外部导出ccall callMeFromC :: IO ()
callMeFromC :: IO()
callMeFromC = B.putStrLncallMeFromC
$ b $ main :: IO()
main = do
B .putStrLnmain
callMeFromHaskell
return()

cc:


  #include  

void callMeFromC(void);

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

Makefile:

  GHC_OPT:= -Wall -O2 -fno-warn -unused-do-bind 

全部:ffiso

测试:ffiso
./$<

ffiso:FFISo.hs cc
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 co FFISo.o

编译和链接工作正常:

  $ make test 
ghc --make -Wall -O2 -fno-warn -unused-do-bind FFISo.hs cc -o ffiso
[1的1]编译主(FFISo.hs,FFISo.o)
链接ffiso ...
./ffiso

callMeFromHaskell
callMeFromC

但是,如果我想使用GHCi,它会失败并显示以下消息:


  $ make ghci0 
echo main | ghci FFISo.hs
GHCi,版本7.4.1:http://www.haskell.org/ghc/:?寻求帮助
加载包ghc-prim ...链接...完成。
加载包integer-gmp ...链接...完成。
加载程序包库...链接...完成。
好​​的,加载的模块:Main。
Prelude Main>加载包bytestring-0.9.2.1 ...正在链接...完成。
< interactive> ;: FFISo.o:未知符号`callMeFromHaskell'

Prelude Main>离开GHCi。

好吧,让我们试着给GHCi co <​​/ code> objectfile。

  $ make ghci1 
echo main | ghci FFISo.hs c.o
GHCi,版本7.4.1:http://www.haskell.org/ghc/:?寻求帮助
加载包ghc-prim ...链接...完成。
加载包integer-gmp ...链接...完成。
加载程序包库...链接...完成。
加载对象(静态)co ...完成
ghc:co:未知符号`callMeFromC'
链接额外库/对象失败
make:*** [ghci1]错误1
最终链接...

哦好吧...让我们试试FFISo.o :


  $ make ghci2 
echo main | ghci FFISo.hs c.o FFISo.o
GHCi,版本7.4.1:http://www.haskell.org/ghc/:?寻求帮助
加载包ghc-prim ...链接...完成。
加载包integer-gmp ...链接...完成。
加载程序包库...链接...完成。
加载对象(静态)co ...完成
加载对象(静态)FFISo.o ...完成
ghc:FFISo.o:未知符号`bytestringzm0zi9zi2zi1_DataziByteStringziInternal_PS_con_info'
链接额外的库/对象失败
make:*** [ghci2]错误1
最终链接...

这就是我被卡住的地方。



我测试了两种不同的环境,结果相同:

  $#system 1 
$ ghc --version
Glorious Glasgow Haskell编译系统,版本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处理器AuthenticAMD GNU / Linux

$#system 2
$ ghc --version
Glorious Glasgow Haskell编译系统,版本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对象 co <​​/ code>在连接时特别挑剔首先,你需要添加 bytestring 包的目标文件。这是通过在GHCi命令行中添加 -package bytestring 来完成的。

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

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

...并且一旦程序启动就会导致运行时崩溃,因为function值的 foo 无法评估。



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

总而言之,调用GHCi时需要使用以下命令行:

  ghci -package bytestring FFISo.o co FFISo_stub.o FFISo.hs 


I have a problem regarding FFI in Haskell and the interactive mode of GHC.

(Source is also available via a 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 ()

c.c:

#include <stdio.h>

void callMeFromC(void);

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

Makefile:

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

Compiling and linking works fine:

$ 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

However, if I want to use GHCi, it fails with this message:

$ 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.

Well, let's try giving GHCi the c.o objectfile.

$ 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 ... 

Oh okay... let's try with 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 ... 

And that's where I'm stuck.

I tested it with two different environments with the same result:

$ # 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

解决方案

You need to specify some more objects to link when invoking GHCi, because the C object c.o is particularly picky when it comes to linking order.

First, you need to add the bytestring package's object files. This is done by adding -package bytestring to the GHCi command line.

Then, you need to add the actual object file that defines callMeFromC. When FFISo.hs is compiled, it doesn't produce an object file that exports callMeFromC. It instead uses the GHC naming convention and exports Main_zdfcallMeFromCzuak4_closure, which actually is a static global variable pointing to the closure/"thunk" that contains the actual function definition and environment. This is so that you can't write something like this:

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

...and have the runtime crash as soon as the program starts because the "function value" of foo can't be evaluated. The function definition is only inspected once the function is actually used.

GHC generates a stub file, which contains C code for calling the Haskell function from C. This file is called FFISo_stub.c, and is compiled into FFISo_stub.o for you. This object file exports the "C version" of callMeFromC that can be called directly. Feel free to inspect the generated code, it is quite interesting.

All in all, you need to use this command line when invoking GHCi:

ghci -package bytestring FFISo.o c.o FFISo_stub.o FFISo.hs

这篇关于GHCi不适用于FFI导出声明/共享库的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆