Haskell FFI:缺少(或错误的)C 库

Haskell FFI: Missing (or bad) C library

我正在尝试使用 FFI 绑定到 Haskell 中的 C 库,但我收到“缺少(或错误的)C 库”。

我在 Ubuntu Linux 上使用 Haskell Tool Stack 2.7.3。我做了一个最小的可复制示例,如下所示。

这是我 运行 stack build:

时的错误信息
Building all executables for `c' once. After a successful build of all of them, only specified executables will be rebuilt.
c> configure (lib + exe)
Configuring c-0.0.0...
Cabal-simple_mPHDZzAJ_3.2.1.0_ghc-8.10.7: Missing dependency on a foreign
library:
* Missing (or bad) C library: small
This problem can usually be solved by installing the system package that
provides this library (you may need the "-dev" version). If the library is
already installed but in a non-standard location then you can use the flags
--extra-include-dirs= and --extra-lib-dirs= to specify where it is.If the
library file does exist, it may contain errors that are caught by the C
compiler at the preprocessing stage. In this case you can re-run configure
with the verbosity flag -v3 to see the error messages.


--  While building package c-0.0.0 (scroll up to its section to see the error) using:
      /home/t/.stack/setup-exe-cache/x86_64-linux-tinfo6/Cabal-simple_mPHDZzAJ_3.2.1.0_ghc-8.10.7 --builddir=.stack-work/dist/x86_64-linux-tinfo6/Cabal-3.2.1.0 configure --user --package-db=clear --package-db=global --package-db=/home/t/.stack/snapshots/x86_64-linux-tinfo6/789c3ce353623de67e3141c688e7a5c70e1e6d9a517056f87d6850c406d11f12/8.10.7/pkgdb --package-db=/home/t/c/.stack-work/install/x86_64-linux-tinfo6/789c3ce353623de67e3141c688e7a5c70e1e6d9a517056f87d6850c406d11f12/8.10.7/pkgdb --libdir=/home/t/c/.stack-work/install/x86_64-linux-tinfo6/789c3ce353623de67e3141c688e7a5c70e1e6d9a517056f87d6850c406d11f12/8.10.7/lib --bindir=/home/t/c/.stack-work/install/x86_64-linux-tinfo6/789c3ce353623de67e3141c688e7a5c70e1e6d9a517056f87d6850c406d11f12/8.10.7/bin --datadir=/home/t/c/.stack-work/install/x86_64-linux-tinfo6/789c3ce353623de67e3141c688e7a5c70e1e6d9a517056f87d6850c406d11f12/8.10.7/share --libexecdir=/home/t/c/.stack-work/install/x86_64-linux-tinfo6/789c3ce353623de67e3141c688e7a5c70e1e6d9a517056f87d6850c406d11f12/8.10.7/libexec --sysconfdir=/home/t/c/.stack-work/install/x86_64-linux-tinfo6/789c3ce353623de67e3141c688e7a5c70e1e6d9a517056f87d6850c406d11f12/8.10.7/etc --docdir=/home/t/c/.stack-work/install/x86_64-linux-tinfo6/789c3ce353623de67e3141c688e7a5c70e1e6d9a517056f87d6850c406d11f12/8.10.7/doc/c-0.0.0 --htmldir=/home/t/c/.stack-work/install/x86_64-linux-tinfo6/789c3ce353623de67e3141c688e7a5c70e1e6d9a517056f87d6850c406d11f12/8.10.7/doc/c-0.0.0 --haddockdir=/home/t/c/.stack-work/install/x86_64-linux-tinfo6/789c3ce353623de67e3141c688e7a5c70e1e6d9a517056f87d6850c406d11f12/8.10.7/doc/c-0.0.0 --dependency=base=base-4.14.3.0 --extra-include-dirs=/home/t/c/src --extra-lib-dirs=/home/t/c/src --exact-configuration --ghc-option=-fhide-source-paths
    Process exited with code: ExitFailure 1

我的 package.yaml 文件:

name:                c

dependencies:
- base >= 4.7 && < 5

library:
  source-dirs: src
  extra-libraries: small

executables:
  c-exe:
    main:                Main.hs
    source-dirs:         app
    ghc-options:
    - -threaded
    - -rtsopts
    - -with-rtsopts=-N
    dependencies:
    - c

包含绑定的 src/Lib.hs 文件:

{-# LANGUAGE ForeignFunctionInterface #-}
{-# LANGUAGE CApiFFI #-}

module Lib
    ( x
    ) where

import qualified Foreign.C.Types as F

foreign import capi "small.h x" x :: IO F.CInt

src/small.c 文件:

#include "small.h"

int x() {
    return 0;
}

src/small.h 文件:

int x();

我首先编译了 C 代码:

gcc -c -o src/small.o src/small.c

我的 stack.yaml 文件:

resolver:
  url: https://raw.githubusercontent.com/commercialhaskell/stackage-snapshots/master/lts/18/20.yaml

extra-include-dirs:
  - src

extra-lib-dirs:
  - src

为方便起见,我将这个最小示例放在 Github:

git clone https://github.com/8n8/haskell-c-ffi-minimal
cd haskell-c-ffi-minimal
stack build

package.yaml 文件的 library 部分,将其更改为

library:
  source-dirs: src
  c-sources:
    - src/small.c

并且 stack.yaml 文件可以减少到

resolver:
  url: https://raw.githubusercontent.com/commercialhaskell/stackage-snapshots/master/lts/18/20.yaml

并且无需执行单独的步骤来编译 C 代码。