15
votes

I am making a small Haskell game in Windows, where I would like to respond each time the user presses a key. Because getChar behaves strangely on Windows, I use FFI to get access to getch in conio.h, as described here. The relevant code is:

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

This works fine, when I run it in ghci, or compile it with ghc. I also want to try making a cabal package out of it, so extending from this question, I include the following in my cabal file:

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

But when I run cabal configure, it tells me:

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

It makes sense, because in my haskell platform directory, under ...\Haskell Platform\2012.4.0.0\mingw there is a conio.h file under the include directory, but no other conio file to provide the object code.

Am I doing this the right way, and if so, how can I find out which library to include in my cabal file?

1
There are various libraries that provide the conio functions. Have you tried Extra-Libraries: crtdll or Extra-Libraries: msvcrt? By the way, according to MSDN, you should use _getch instead of getch, but the header file might do that for you.user824425
Note that this only affects ghc/ghci in Windows, and the solution code doesn't work in WinHugs in particular, so you need it to only compile with this when it's specifically Windows/ghc.AndrewC
@Tinctorius I have just tried Extra-libraries: msvcrt and Extra-libraries: crtdll alone and in combination. It didn't change the output of cabal build. I found msvcrt.lib and crtdll.c under my visual studio installation, and copied them to my folder, but it didn't change anything.Boris
@Boris: if you say Extra-Libraries: NAME, Cabal should be looking for ...\Haskell Platform\2012.4.0.0\mingw\lib\libNAME.a. I have libcrtdll.a in that directory, so a dependency on crtdll works fine for me. Have you tried supplying the --extra-lib-dirs parameter to cabal, pointing to that directory?user824425
@Tinctorius: I now have Extra-libraries: crtdll in my cabal file. I have the file libcrtdll.a under ...\Haskell Platform\2012.4.0.0\mingw\lib, and I have configured cabal with the extra-lib-dirs="(Path to lib dir)" flag. I now get the error: parse error on input 'import, so it's different. B.t.w., I thought cabal would include the lib folder by default?Boris

1 Answers

7
votes

First off, there is not always a one-to-one mapping between C header files and libraries. In this case, the functions declared in conio.h can be found in various runtime libraries, such as crtdll (deprecated) or msvcrt (preferred, I guess).

With the Haskell Platform on Windows, Cabal will look for these libraries in .\mingw\lib (under your Haskell Platform directory): if you ask for msvcrt, it will look for .\mingw\lib\libmsvcrt.a. This specific library should already be shipped with your Haskell Platform. (If you want to point to other directories with lib*.a files, you can use Cabal's --extra-lib-dirs option.)

A tiny example of this would be as follows; this is 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'

And this would be 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

This should work fine:

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
!