首先,我指定我使用Windows 10 64位和Haskell平台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'
(当我运行后input1)
但是,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>
我试图加载“缺less的库”,比如需要使用conio.h
“ -lmsvcrt
”,但结果是悲观的。
> 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-code
, ghci -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
find了哪ghc Examples.hs -v5
。
可悲的是,没有什么为我的main
工作,我找不到任何其他途径。
PS有谁知道如何在Windows中使用hSetBuffering(它在8年前发布在ghc ticket#2189中 ,是不是固定的?)
这是因为在Windows上没有getch
。 getch
是POSIX,POSIX在Windows上已被弃用。 它仍然在,但功能已被移到不同的命名空间(释放根命名空间到用户程序)。 正如你可以看到MSDN所说, getch
已被弃用https://msdn.microsoft.com/en-us/library/ms235446.aspx,并使用_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
项目从来没有像微软那样去掉弃用的功能
因此
$ 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
时会发生什么:
在编译模式下,GCC和GHC都会首先选择静态库,这恰好是一个导入库libmsvcrt.dll.a
。 这是由于链接器(ld)的链接顺序。
在解释模式下,GHCi将始终偏好静态库的动态版本。 原因是在重新链接期间(在引入新的作用域或重新加载时发生),动态库的速度要快得多,因为我们不需要在内部进行重定位和符号解析。 还有一些东西我们还是不能像弱符号或者普通符号那样正确支持,所以出于这些原因我们只是喜欢动态的。
GHCi 8.0.1不支持导入库。 因此,虽然你可以强制GHCi使用静态库(只需要给全名-l
,例如-llibmsvcr.a
),它不会工作,因为运行时加载器不知道如何处理它。 但是,这在目前的GIT大师支持,可能会在8.0.2