Windows中具有GHCI的Haskell外部功能接口

俊扬·克莱尔·张

首先,我指定使用Windows 10 64bit和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:
  [email protected]

*Main>

我尝试加载“ missing library”,例如-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:
  [email protected]

*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,并且我找不到其他任何方式。

PS有没有人知道如何在Windows中使用hSetBuffering(它发布于8年前的ghc票号#2189中。不是固定的吗?)

y

这是因为getchWindows上没有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项目从未像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之间不兼容的根源。

但是,Microsoft已删除它们

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

所以会发生什么,当你对链接msvcrt

  1. 在编译模式下,GCC和GHC都将首先选择静态库,该库恰好是import lib libmsvcrt.dll.a这是由于链接器(ld)的链接顺序。

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

  3. GHCi 8.0.1不支持导入库。因此,尽管您可以强制GHCi使用静态库(只需将全名指定为-l,例如-llibmsvcr.a),但它不会起作用,因为运行时加载程序不知道如何处理它。但是,当前的GIT主机支持此功能,并且很可能会在8.0.2

本文收集自互联网,转载请注明来源。

如有侵权,请联系[email protected] 删除。

编辑于
0

我来说两句

0条评论
登录后参与评论

相关文章

来自分类Dev

Windows中具有GHCI的Haskell外部功能接口

来自分类Dev

具有通用throw子句的Lambda和功能接口

来自分类Dev

Callable <Void>作为具有lambda的功能接口

来自分类Dev

空在具有不同类型的返回功能接口

来自分类Dev

Java 8中的功能接口的定义

来自分类Dev

Lambda中的歧义功能接口

来自分类Dev

无法将具有泛型方法的功能接口转换为lambda表达式

来自分类Dev

如何为具有泛型方法的功能接口创建Lambda表达式

来自分类Dev

使用具有自定义功能接口的流

来自分类Dev

具有功能接口的Java-8 Lambda表达式行为

来自分类Dev

具有功能接口的Java-8 Lambda表达式行为

来自分类Dev

如果功能接口具有多个非默认方法,则提示不会显示错误消息

来自分类Dev

使用具有自定义功能接口的流

来自分类Dev

功能接口

来自分类Dev

Java8中是否有标准化的通用功能接口?

来自分类Dev

在Java 8中使用功能接口

来自分类Dev

Java 7中Java 8的功能接口

来自分类Dev

返回Java 8中的通用功能接口

来自分类Dev

投java.lang.reflect.Method中的功能接口

来自分类Dev

实现记录语法中定义的功能接口?

来自分类Dev

是否可以从java中的功能接口返回地图响应

来自分类Dev

通用功能接口

来自分类Dev

功能接口继承怪癖

来自分类Dev

识别内置功能接口

来自分类Dev

使Multiline Haskell功能在ghci中工作

来自分类Dev

有没有办法将现有接口转换为功能接口?

来自分类常见问题

功能接口,功能方法和lamda?

来自分类Dev

通用功能作为功能接口?

来自分类Dev

接口在Java中具有相同功能的原型?