Зависимость FFI

Я делаю небольшую игру Haskell в Windows, где я бы хотел отвечать каждый раз, когда пользователь нажимает клавишу. Поскольку getChar ведет себя странно в Windows, я использую FFI для доступа к getch в conio.h, как описано . Соответствующий код:

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

Это отлично работает, когда я запускаю его в ghci или компилирую его с помощью ghc. Я также хочу попытаться сделать из нее пакет для каббала, поэтому, простираясь от этого вопроса, я включаю в свой файл 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\mingw есть файл conio.h в каталоге include, но нет другого файла conio для предоставления объектного кода.

Я делаю это правильно, и если да, то как я могу узнать, какую библиотеку включить в мой файл cabal?

Ответ 1

Во-первых, между файлами заголовков C и библиотеками не всегда существует взаимно однозначное сопоставление. В этом случае функции, объявленные в conio.h, могут быть найдены в различных библиотеках времени исполнения, таких как crtdll (устаревший) или msvcrt (предпочтительнее, я думаю).

С платформой Haskell в Windows Cabal будет искать эти библиотеки в .\mingw\lib (в вашем каталоге Haskell Platform): если вы попросите 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
!