[Haskell-beginners] FFI and Cabal

Jeffrey Drake iaefai at me.com
Mon Nov 23 02:35:00 EST 2009

I am trying to use FFI to access some windows console functions via two simple C functions I created.

Essentially my module looks like is this: 

{-# CFILES mouse.c #-}
{-# LANGUAGE ForeignFunctionInterface #-}
module Mouse where 
-- import Foreign
import Foreign.C.Types

foreign import ccall unsafe "mouse.h SetupConsole" c_setupConsole :: IO CInt
foreign import ccall unsafe "mouse.h MouseEvent" c_mouseEvent :: IO CInt

setupConsole :: IO Bool
setupConsole = do   c <- c_setupConsole
                    return $ if c == 0
                        then True
                        else False

mouseEvent :: IO (Maybe (Int, Int))
mouseEvent = do	c <- c_mouseEvent
                let d = toInteger c
                let e = (fromInteger d)::Int
                return $ if e < 0
                    then Nothing
                    else Just (e `mod` 256, e `div` 256)

It seems to compile fine. The problem comes when I need to link.
Linking dist\build\BoardGames\BoardGames.exe ...
dist\build\BoardGames\BoardGames-tmp\Mouse.o:fake:(.text+0x15): undefined reference to `SetupConsole'
dist\build\BoardGames\BoardGames-tmp\Mouse.o:fake:(.text+0x11d): undefined reference to `MouseEvent'
collect2: ld returned 1 exit status

The problem seems obvious - it isn't compiling OR linking mouse.c which is this:

#include <windows.h>

int SetupConsole()
    HANDLE hStdin; 
    DWORD fdwMode, fdwSaveOldMode; 
    int counter=0;
    hStdin = GetStdHandle(((DWORD)-10)); 
    if (hStdin == ((HANDLE)(LONG_PTR)-1)) 
        return -3; 
    if (! GetConsoleMode(hStdin, &fdwSaveOldMode) ) 
        return -2;
    fdwMode = 0x0010; 
    if (! SetConsoleMode(hStdin, fdwMode) ) 
        return -1;
	return 0;

int MouseEvent()
	HANDLE hStdin;
	INPUT_RECORD irInBuf[128];
	short x, y;
	unsigned i;
	DWORD cNumRead;

	static int ignoreNext = 0;

	hStdin = GetStdHandle(((DWORD)-10)); 
    if (hStdin == ((HANDLE)(LONG_PTR)-1)) 
		return -2;

	if (!ReadConsoleInputW( 
                &cNumRead) ) 
            return -1;

   for (i = 0; i < cNumRead; i++) 
			if (irInBuf[i].EventType == 0x0002 && irInBuf[i].Event.MouseEvent.dwEventFlags == 0)
				if (ignoreNext == 1)
					ignoreNext = 0;
					return -1;
				x = irInBuf[i].Event.MouseEvent.dwMousePosition.X;
				y = irInBuf[i].Event.MouseEvent.dwMousePosition.Y;

				ignoreNext = 1;

				return x + (y << 8);
   return -1;

So far, I have only tested this with MSVC (it works), but not with haskell platform's mingw (which includes windows.h - so I would have to wait for this...)

In my cabal file I have:
 c-sources:		mouse.c

So that basically sums up what I have, I just don't know how to do this. The cabal documentation says for this directive:

c-sources: filename list
A list of C source files to be compiled and linked with the Haskell files.

Which is what I expected it to do - but to no avail.

I should note that when I try to comment out with -- the c-sources line I get this:

Linking dist\build\BoardGames\BoardGames.exe ...
dist\build\BoardGames\BoardGames-tmp\Main.o:fake:(.text+0x27d): undefined reference to `__stginit_Mouse_'
dist\build\BoardGames\BoardGames-tmp\Main.o:fake:(.text+0xb4): undefined reference to `Mouse_a1_info'
dist\build\BoardGames\BoardGames-tmp\Main.o:fake:(.text+0xcc): undefined reference to `Mouse_czusetupConsole_info'
dist\build\BoardGames\BoardGames-tmp\Main.o:fake:(.text+0xf8): undefined reference to `Mouse_a1_info'
dist\build\BoardGames\BoardGames-tmp\Main.o:fake:(.text+0x17a): undefined reference to `Mouse_czusetupConsole_info'
dist\build\BoardGames\BoardGames-tmp\Main.o:fake:(.data+0x14): undefined reference to `Mouse_a1_closure'
collect2: ld returned 1 exit status

Any help that can be offered would be appreciated.

I would tell you where to find the project, but patch-tag is being unavailable for me at this time. It is the 'BoardGames' project, under iaefai.

Thank you again,

More information about the Beginners mailing list