First of all, I specify that I use Windows 10 64bit and Haskell Platform 8.0.1.
I try to use FFI of Haskell in Windows using following code.
import Control.Monad
import Data.Char
import Foreign.C
getCh :: IO Char
getCh = liftM (chr . fromEnum) c_getch
foreign import ccall unsafe "conio.h getch" c_getch :: IO CInt
main :: IO ()
main = getCh >>= \x -> print x
After this, I can compile this well with ghc
> ghc Examples.hs
[1 of 1] Compiling Main ( Examples.hs, Examples.o )
Linking Examples.exe ...
and it runs completely.
> Examples.exe
'1'
(When I type 1 after running it)
However, the problem occurs with GHCI. When I load it to ghci, I got these messages.
> ghci Examples.hs
GHCi, version 8.0.1: http://www.haskell.org/ghc/ :? for help
[1 of 1] Compiling Main ( Examples.hs, interpreted )
Ok, modules loaded: Main.
*Main> main
ByteCodeLink: can't find label
During interactive linking, GHCi couldn't find the following symbol:
getch
This may be due to you not asking GHCi to load extra object files,
archives or DLLs needed by your current session. Restart GHCi, specifying
the missing library using the -L/path/to/object/dir and -lmissinglibname
flags, or simply by naming the relevant files on the GHCi command line.
Alternatively, this link failure might indicate a bug in GHCi.
If you suspect the latter, please send a bug report to:
[email protected]
*Main>
I try to load "missing library", such as "-lmsvcrt
" which needs to use conio.h
, but result is pessimistically same.
> ghci -lmsvcrt Examples.hs
GHCi, version 8.0.1: http://www.haskell.org/ghc/ :? for help
[1 of 1] Compiling Main ( Examples.hs, interpreted )
Ok, modules loaded: Main.
*Main> main
ByteCodeLink: can't find label
During interactive linking, GHCi couldn't find the following symbol:
getch
This may be due to you not asking GHCi to load extra object files,
archives or DLLs needed by your current session. Restart GHCi, specifying
the missing library using the -L/path/to/object/dir and -lmissinglibname
flags, or simply by naming the relevant files on the GHCi command line.
Alternatively, this link failure might indicate a bug in GHCi.
If you suspect the latter, please send a bug report to:
[email protected]
*Main>
GHCI probably loads the library, since when I try to load a wrong library, ghci prints errors about that.
I try several other things, like using ghci Examples.hs -fobject-code
, ghci -lmsvcrt Examples.hs -fobject-code
, and even
ghci Examples.hs "-luser32" "-lgdi32" "-lwinmm" "-ladvapi32" "-lshell32"
"-lshfolder" "-lwsock32" "-luser32" "-lshell32" "-lmsvcrt" "-lmingw32"
"-lmingwex" "-luser32" "-lmingw32" "-lmingwex" "-lm" "-lwsock32" "-lgdi32" "-lwinmm"
Which was found in ghc Examples.hs -v5
.
Sadly, Nothing works for my main
, and I can't find any otherway for this.
P.S. Is there anyone knowing how to use hSetBuffering in Windows (It was posted at 8 years ago in ghc ticket #2189. Isn't it fixed?)
This is because there is no getch
on Windows. getch
is POSIX and POSIX has been deprecated on Windows. It's still around but the functions have been moved to a different namespace (to free up the root namespace to user programs). As you can see MSDN says getch
is deprecated https://msdn.microsoft.com/en-us/library/ms235446.aspx and to use _getch
instead.
import Control.Monad
import Data.Char
import Foreign.C
getCh :: IO Char
getCh = liftM (chr . fromEnum) c_getch
foreign import ccall unsafe "conio.h _getch" c_getch :: IO CInt
main :: IO ()
main = getCh >>= \x -> print x
Will work both compiled and interpreted.
As to the why it works compiled and not interpreted when using getch
:
The MingW-w64
project has never removed deprecated functions as Microsoft has
As such
$ objdump -t /home/Tamar/ghc2/inplace/mingw/x86_64-w64-mingw32/lib/libmsvcr120.a | grep getch
[ 7](sec 1)(fl 0x00)(ty 0)(scl 2) (nx 0) 0x0000000000000000 getch
[ 8](sec 5)(fl 0x00)(ty 0)(scl 2) (nx 0) 0x0000000000000000 __imp_getch
[ 7](sec 1)(fl 0x00)(ty 0)(scl 2) (nx 0) 0x0000000000000000 _getch
[ 8](sec 5)(fl 0x00)(ty 0)(scl 2) (nx 0) 0x0000000000000000 __imp__getch
getch
is being redirected to _getch
and so they have both versions. This is a source of incompatibility between MSVC++ and GCC.
Microsoft however has removed them
>dumpbin /exports C:\Windows\System32\msvcr120.dll | findstr getch
699 2BA 0006B8B4 _getch = _getch
So what happens, when you link against msvcrt
:
In compiled mode both GCC and GHC will pick the static library first which happens to be an import lib libmsvcrt.dll.a
. This is due to the link order of the linker (ld).
In interpreted mode, GHCi will always prefer the dynamic version of the library over the static one. The reason is during re-linking (which has to happen when you introduce a new scope or reload) dynamic libraries are much faster as we don't have to internally do relocations and symbol resolving. There are also things we still don't support properly like weak symbols or common symbols, so for these reasons we just prefer the dynamic one.
GHCi 8.0.1 does not support import libraries. So while you can force GHCi to use the static library (just give the full name to -l
, e.g. -llibmsvcr.a
) It won't work because the runtime loader doesn't know what to do with it. This is however supported in the current GIT master and will likely be in 8.0.2