Windows中使用GHCI的Haskell外部函数接口

时间:2016-07-09 14:01:54

标签: windows haskell ffi ghci console-input

首先,我指定使用Windows 10 64位和Haskell Platform 8.0.1。

我尝试使用以下代码在Windows中使用Haskell的FFI。

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

在此之后,我可以用ghc

编译好
> ghc Examples.hs
[1 of 1] Compiling Main             ( Examples.hs, Examples.o )
Linking Examples.exe ...

它完全运行。

> Examples.exe
'1'

(当我在运行后输入1时)

然而,GHCI会出现问题。当我把它加载到ghci时,我收到了这些消息。

> 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:
  glasgow-haskell-bugs@haskell.org

*Main>

我尝试加载"缺少库",例如" -lmsvcrt"需要使用conio.h,但结果与悲观相同。

> 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:
  glasgow-haskell-bugs@haskell.org

*Main>

GHCI可能会加载库,因为当我尝试加载错误的库时,ghci会输出错误。

我尝试了其他一些内容,例如使用ghci Examples.hs -fobject-codeghci -lmsvcrt Examples.hs -fobject-code甚至

ghci Examples.hs "-luser32" "-lgdi32" "-lwinmm" "-ladvapi32" "-lshell32"
"-lshfolder" "-lwsock32" "-luser32" "-lshell32" "-lmsvcrt" "-lmingw32" 
"-lmingwex" "-luser32" "-lmingw32" "-lmingwex" "-lm" "-lwsock32" "-lgdi32" "-lwinmm"

ghc Examples.hs -v5中找到了。

可悲的是,我的main没有任何作用,我无法找到其他任何方式。

P.S。有没有人知道如何在Windows中使用hSetBuffering(它发布于8年前ghc ticket #2189。是不是已经修复了?)

1 个答案:

答案 0 :(得分:1)

这是因为Windows上没有getchgetch是POSIX,POSIX已在Windows上弃用。它仍然存在,但函数已被移动到不同的命名空间(以将根命名空间释放到用户程序)。正如您所看到的,MSDN说getch已被弃用[{3}},而是使用_getch

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

既可以编译也可以解释。

关于使用getch时编译和解释的原因:

MingW-w64项目从未删除已弃用的功能,如Microsoft已经

就这样

$ 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被重定向到_getch,因此他们有两个版本。这是MSVC ++和GCC之间不兼容的原因。

但微软已将其删除

>dumpbin /exports C:\Windows\System32\msvcr120.dll | findstr getch
        699  2BA 0006B8B4 _getch = _getch

当你链接到msvcrt

时会发生什么
  1. 在编译模式下,GCC和GHC将首先选择静态库,这恰好是一个导入库libmsvcrt.dll.a。这是由于链接器(ld)的链接顺序。

  2. 在解释模式下,GHCi 总是更喜欢库的动态版本而不是静态版本。原因是在重新链接期间(必须在引入新范围或重新加载时发生)动态库要快得多,因为我们不必在内部执行重定位和符号解析。还有一些我们仍然不能正确支持的东西,如弱符号或常见符号,因此出于这些原因,我们更喜欢动态符号。

  3. GHCi 8.0.1不支持导入库。因此,虽然您可以强制GHCi使用静态库(只需将全名命名为-l,例如-llibmsvcr.a)它将无法工作,因为运行时加载程序不知道如何处理它。但是,当前的GIT主数据支持此功能,可能会在8.0.2