【问题标题】:cabal FFI dependency阴谋集团 FFI 依赖
【发布时间】:2012-11-24 19:15:45
【问题描述】:

我正在 Windows 中制作一个小型 Haskell 游戏,我想在用户每次按键时做出响应。因为 getChar behaves strangely 在 Windows 上,我使用 FFI 来访问 conio.h 中的 getch,如 here 所述。相关代码为:

foreign import ccall unsafe "conio.h getch" c_getch :: IO CInt

当我在 ghci 中运行它或使用 ghc 编译它时,这很好用。我还想尝试用它制作一个 cabal 包,因此从this 问题扩展,我在我的 cabal 文件中包含以下内容:

...
executable noughts
  Includes:          conio.h
  Extra-libraries    conio
...

但是当我运行cabal configure 时,它告诉我:

cabal: Missing dependency on a foreign library:
* Missing C library: conio

这是有道理的,因为在我的haskell平台目录下,...\Haskell Platform\2012.4.0.0\mingwinclude目录下有一个conio.h文件,但没有其他conio文件提供目标代码。

我这样做的方式是否正确,如果是,我如何找出要包含在我的 cabal 文件中的库?

【问题讨论】:

  • 提供 conio 函数的库有很多。你试过Extra-Libraries: crtdllExtra-Libraries: msvcrt 吗?顺便说一句,根据 MSDN,您应该使用 _getch 而不是 getch,但头文件可能会为您做到这一点。
  • 请注意,这只会影响 Windows 中的 ghc/ghci,并且解决方案代码在 WinHugs 中尤其不起作用,因此您需要它仅在特定于 Windows/ghc 时使用它进行编译。跨度>
  • @Tinctorius 我刚刚尝试了 Extra-libraries: msvcrtExtra-libraries: crtdll 单独和组合。它没有改变cabal build 的输出。我在我的 Visual Studio 安装下找到了 msvcrt.libcrtdll.c,并将它们复制到我的文件夹中,但它没有改变任何东西。
  • @Boris:如果你说Extra-Libraries: NAME,Cabal 应该在寻找...\Haskell Platform\2012.4.0.0\mingw\lib\libNAME.a。我在那个目录中有libcrtdll.a,所以对crtdll 的依赖对我来说很好。您是否尝试将--extra-lib-dirs 参数提供给cabal,指向该目录?
  • @Tinctorius:我的 cabal 文件中现在有 Extra-libraries: crtdll。我在...\Haskell Platform\2012.4.0.0\mingw\lib 下有文件libcrtdll.a,并且我已经使用extra-lib-dirs="(Path to lib dir)" 标志配置了cabal。我现在得到错误:parse error on input 'import,所以它有所不同。顺便说一句,我认为 cabal 默认会包含 lib 文件夹?

标签: haskell cabal ffi conio


【解决方案1】:

首先,C 头文件和库之间并不总是一对一的映射。在这种情况下,conio.h 中声明的函数可以在各种运行时库中找到,例如crtdll(已弃用)或msvcrt(我猜是首选)。

使用 Windows 上的 Haskell 平台,Cabal 将在 .\mingw\lib(在您的 Haskell 平台目录下)中查找这些库:如果您要求 msvcrt,它将查找 .\mingw\lib\libmsvcrt.a。这个特定的库应该已经随您的 Haskell 平台一起提供。 (如果你想用lib*.a文件指向其他目录,你可以使用Cabal的--extra-lib-dirs选项。)

这方面的一个小例子如下;这是Main.hs

{-# LANGUAGE ForeignFunctionInterface #-}
import Foreign.C.Types
foreign import ccall unsafe "conio.h _putch" c_putch :: CInt -> IO ()

main :: IO ()
main = do
    c_putch . toEnum . fromEnum $ '!'
    c_putch . toEnum . fromEnum $ '\n'

这将是something-awesome.cabal:

name:                something-awesome
version:             0.1.0.0
build-type:          Simple
cabal-version:       >=1.8

executable yay
  main-is:             Main.hs
  build-depends:       base ==4.5.*

  includes:            conio.h
  extra-libraries:     msvcrt

这应该可以正常工作:

c:\tmp\something-awesome> dir /B
Main.hs
something-awesome.cabal

c:\tmp\something-awesome> cabal configure
Resolving dependencies...
Configuring something-awesome-0.1.0.0...

c:\tmp\something-awesome> cabal build
Building something-awesome-0.1.0.0...
Preprocessing executable 'yay' for something-awesome-0.1.0.0...
[1 of 1] Compiling Main             ( Main.hs, dist\build\yay\yay-tmp\Main.o )
Linking dist\build\yay\yay.exe ...

c:\tmp\something-awesome> dist\build\yay\yay.exe
!

【讨论】:

  • 为了将来参考,有没有什么地方可以查到哪个库提供了功能?您是如何发现 _getch 是由 msvcrt 和 crtdll 提供的,而后者已被弃用?简单的谷歌搜索没有发现任何东西。
  • MSDN 是(一个糟糕的尝试)规范的 Windows 开发手册,它通常提供用于给定函数的头文件和库(您可以使用 Google 的 site: 运算符搜索它)。 _getch and friends 上的文章只提到“所有版本的 C 运行时库”都支持它。在我的lib 目录(CRT = C 运行时)中找到libcrtdll.alibmsvcrt.a 后,我在Google 上搜索crtdllmsvcrt 之间的区别,发现前者是来自Windows 95 时代。
  • @谢谢,出色的侦探工作。是的,MSDN 似乎并不完全旨在引导您直接获得所需的信息 :)
  • 我在 GHCJS 上遇到了同样的问题,“外国导入 javascript”(反射平台)现在解决了。谢谢!
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2014-07-04
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多