我想用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 编译器为其生成一个目标文件,以便您的 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
您可能还需要指定
includes
和 include-dirs
,例如:
includes: nuklear.h