如何使用 Haskell 的 C 库?

Ber*_*ian 4 c interop haskell ffi

我尝试使用 FFI 从 Haskell 调用 C 函数,但不断收到此错误:

ghc.exe:^^ 无法加载“getSize”,依赖性未解决。请参阅上面的顶部条目。

main: ByteCodeLink: can't find label 在交互式链接期间,GHCi 找不到以下符号:getSize 这可能是由于您没有要求 GHCi 加载当前会话所需的额外对象文件、存档或 DLL。重新启动 GHCi,使用 -L/path/to/object/dir 和 -lmissinglibname 标志指定缺少的库,或者只需在 GHCi 命令行上命名相关文件即可。或者,此链接失败可能表明 GHCi 中存在错误。如果您怀疑后者,请将错误报告发送至:
glasgow-haskell-bugs@haskell.org

我正在stdio.h我的 C 库中使用该库:

C库

// lib.h
#include <stdio.h>

double getSize() {
    double size = 0;
    scanf("$f", &size);
    return size;
}
Run Code Online (Sandbox Code Playgroud)

FFI模块

{-# LANGUAGE ForeignFunctionInterface #-}
module Ffi where

import Foreign
import Foreign.C.Types

foreign import ccall "lib.h getSize" c_size :: IO Double
Run Code Online (Sandbox Code Playgroud)

主要的

module Main where
import Ffi

main :: IO ()
main = do a <- getLine
          b <- c_size
          print $ "got from C: " ++ show b
Run Code Online (Sandbox Code Playgroud)

运行脚本

gcc -o lib -lib.h
runghc main
Run Code Online (Sandbox Code Playgroud)

PS这可能是因为我也必须stdio.h在其他地方指定依赖项吗?

K. *_*uhr 9

好的,这里有几件事要做:

  • 将“lib.h”重命名为“lib.c”。它是一个 C 源文件(包含代码),而不是一个 C 头文件。
  • 理想情况下,添加一个单独的“lib.h”头文件以及getSize.
  • 修复“lib.c”中的错误。您希望用“%lf”代替“$f”来读取双精度值。
  • 使用 编译程序ghc而不是使用 运行程序runghc。单个ghc命令可以编译和链接 Haskell 模块和 C 代码。

换句话说,您的文件应该如下所示:

// lib.c
#include "lib.h"
#include <stdio.h>
double getSize() {
    double size = 0;
    scanf("%lf", &size);
    return size;
}
Run Code Online (Sandbox Code Playgroud)
// lib.h
double getSize(void);
Run Code Online (Sandbox Code Playgroud)
-- Ffi.hs
{-# LANGUAGE ForeignFunctionInterface #-}
module Ffi where
import Foreign
import Foreign.C.Types
foreign import ccall "lib.h getSize" c_size :: IO Double
Run Code Online (Sandbox Code Playgroud)
-- Main.hs
module Main where
import Ffi
main :: IO ()
main = do a <- getLine
          b <- c_size
          print $ "got from C: " ++ show b
Run Code Online (Sandbox Code Playgroud)

你应该用以下命令编译它:

$ ghc Main.hs lib.c
[1 of 2] Compiling Ffi              ( Ffi.hs, Ffi.o )
[2 of 2] Compiling Main             ( Main.hs, Main.o )
Linking Main ...
Run Code Online (Sandbox Code Playgroud)

然后你可以运行它,为 Haskell 提供一行getLine,为 C 提供第二行scanf,它应该可以正常工作:

$ ./Main
hello world!!   -- line for Haskell
135.0           -- line for C
"got from C: 135.0"
Run Code Online (Sandbox Code Playgroud)