【问题标题】:Testing FFI Code (with "foreign import"s) with GHCi使用 GHCi 测试 FFI 代码(带有“外国进口”)
【发布时间】:2013-03-28 08:38:59
【问题描述】:

大家好(您的当地时间)。

我在Foreign Function Interface上通过Real World Haskell's chapter, 并做了一些后续阅读here。我现在正在尝试绑定 到 C 函数,我想澄清一些事情。

以下内容相当清楚:

foreign import ccall unsafe "math.h sin" c_sin :: CDouble -> CDouble

我可以加载这个和在 ghci 中使用它的代码,一切都很好。它甚至 以 emacs 的 Haskell 模式加载嵌入式 ghci。我发现这非常适合测试。 math 是一个系统库,所以这很简单。

现在是来自 Real World Haskell 的示例:

foreign import ccall unsafe "pcre.h pcre_compile" c_pcre_compile :: ...

我故意省略了函数签名的其余部分。现在,我无法加载这个 哈斯克尔模式。我见过的所有例子都说必须这样做:

ghci -lpcre

我这样做,并立即确认加载正确:

GHCi, version 7.6.2: 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 (dynamic) /usr/lib/gcc/x86_64-unknown-linux-gnu/4.7.2/../../../../lib/libpcre.so ... done
final link ... done

然后我可以加载我的绑定代码并进行测试,但是...

_问题 1_ 我可以从 ghci 中加载非系统库,比如 pcre 吗?这个会 请允许我在 emacs 中进行测试。

继续前进。 当我尝试编写绑定到我自己的自己的 C 代码时,事情变得更加复杂。

foreign import ccall unsafe "myprint.h myprint" c_myprint :: CString -> IO ()

诚然,这是一个毫无意义的功能。它需要一个来自 Haskell 的 ByteString 和 用 C 打印出来。这是一个简单的测试文件:

{-# LANGUAGE ForeignFunctionInterface #-}
-- printTest.hs

import Foreign
import Foreign.C.Types
import Foreign.C.String

import qualified Data.ByteString.Char8 as B

---

foreign import ccall unsafe "myprint.h myprint" c_myprint :: CString -> IO ()

---

main = B.useAsCString (B.pack "Tempura is great!") c_myprint

我已经能够通过这样做来编译它:

ghc --make myprint.c printTest.hs

并获得一个可执行文件,但我根本无法在 ghci 中加载它。 这严重滞后于测试过程。

_问题 2_ 我必须做什么才能在绑定到 my C 代码的 ghci 中加载 Haskell 代码? FFI 信息的主要来源都没有对此发表任何看法。 再多摆弄ghci -L 也无法让它发挥作用。

请并感谢您提供的任何帮助。

【问题讨论】:

  • Q2,如果你想让 myprint.c 加载到 ghci 中,你必须将它编译为一个库。这取决于 c 编译器/操作系统。
  • 沿着这些线(gcc -c -fPIC foo.c -o foo.o 然后 gcc -shared -Wl,-soname,libfoo.so.1 -o libfoo.so.1.0.1 foo.o) 或类似的东西

标签: haskell ffi ghci


【解决方案1】:

ghci 将加载任何库,只要它对您的架构有效并且可以位于某个路径上。在 windows 上,带有空格的路径名会导致问题,我不知道它们是否仍然存在。

要在 ghci 中加载你自己的代码,你需要先编译它,然后告诉 ghci 加载它的输出:

mybox$ gcc -c myprint.c
mybox$ ghci Myprint.hs myprint.o

*Main> main
Loading package array-0.4.0.1 ... linking ... done.
Loading package deepseq-1.3.0.1 ... linking ... done.
Loading package bytestring-0.10.0.2 ... linking ... done.
Tempura is great!
*Main>

您也可以将 C 文件编译到库中并将其加载到 ghci 中,但是对于仅一个文件,使用目标文件非常方便。如果你想创建一个库,像@Jonke 建议的命令应该可以工作。在我的系统 (OSX) 上,

mybox$ gcc -shared -fPIC myprint.c -o libmyprint.dylib
mybox$ ghci -L. -lmyprint Foo.hs

在我的系统上,它也可以只使用库文件路径作为参数,但我不知道这是否可移植。

【讨论】:

  • ghci myprint.o 这似乎是最简单的方法。谢谢。
  • 如果 myprint.o 依赖于相对目录中包含的静态 C 库(例如:lib/libx.a),我该如何继续
  • @ThiadodeArruda 您需要添加必要的链接器标志,就像您正在编译一样。像-Llib -lx -lmyprint 这样的东西应该可以工作。不过,链接器标志可能对排序很敏感,因此如果您有很多要链接的库,您可能需要做一些工作才能找到正确的排序。
猜你喜欢
  • 2023-04-06
  • 2012-04-24
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2020-10-02
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多