Haskell FFI 本地 C 头文件

4

我希望使用FFI调用一个C单头文件库。

这里是Nuk.hs

{-# LANGUAGE CPP, ForeignFunctionInterface #-}
module Main where

import Foreign
import Foreign.C.Types

foreign import ccall unsafe "nuklear.h nk_sin"
 c_nk_sin:: IO CFloat

main = print $ c_nk_sin (5)

在同一个目录下,我有一个名为nuklear.h的文件。
当我执行stack ghc Nuk.hs时,我会得到以下结果。
[1 of 1] Compiling Main             ( Nuk.hs, Nuk.o )
Linking Nuk ...
Nuk.o:r1Rq_info: error: undefined reference to 'nk_sin'
collect2: error: ld returned 1 exit status
`gcc' failed in phase `Linker'. (Exit code: 1)

我该怎么解决这个问题?


你有带有C端二进制代码的.o文件吗?你需要将它们链接在一起,例如:stack ghc Nuk.hs cside.o。如果你不想进行链接,可以使用-c选项。(之后再进行链接) - chi
@chi,我不知道。C端是一个单一的头文件,应该包含在C程序中。实现也在那个头文件里面。 - McBear Holden
1个回答

5
如果这是一个仅有头文件的库,您需要一个C编译器来为其生成目标文件,以便您的Haskell程序可以链接到定义。根据Nuklear的文档,您可以创建一个存根C文件:
// nuklear.c
#define NK_IMPLEMENTATION
#include "nuklear.h"

作为构建的一部分,编译这个文件(例如使用gcc -c nuklear.c -o nuklear.o),生成一个目标文件nuklear.o,使用ar命令(例如ar -csr libnuklear.a nuklear.o)创建一个静态库libnuklear.a。然后假设这个存档文件在libs文件夹中,您需要添加以下内容:
extra-lib-dirs: libs
extra-libraries: nuklear

在您的Cabal文件中的executable部分(或者对于hpack,相应的package.yml部分)。

为了协调这一点,您可能有一个Makefile来构建此库,并调用stack/cabal/ghc来生成最终的构建结果。这个教程详细介绍了这个过程。但对于这个简单的用例,您可以尝试使用c-sources部分在Cabal内部完成此操作:

c-sources: nuklear.c

您可能还需要指定includesinclude-dirs,例如:

includes: nuklear.h

使用内联C怎么样? - McBear Holden

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接