2016-07-09 7 views
3

Als Erstes gebe ich an, dass ich Windows 10 64bit und Haskell Platform 8.0.1 verwende.Haskell Foreign Function Interface mit GHCI in Windows

Ich versuche, FFI von Haskell in Windows mit folgendem Code zu verwenden.

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 

Danach kann ich diese kompilieren gut mit ghc

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

und es läuft vollständig.

> Examples.exe 
'1' 

(Wenn ich 1 geben, nachdem es ausgeführt wird)

tritt jedoch das Problem mit GHCI. Wenn ich es nach Ghci lade, habe ich diese Nachrichten bekommen.

> 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> 

Ich versuche, „fehlende Bibliothek“, wie „-lmsvcrt“ zu laden, die conio.h verwenden muss, aber Ergebnis ist pessimistisch gleich.

> 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 lädt wahrscheinlich die Bibliothek, da, wenn ich eine falsche Bibliothek zu laden, GHCI druckt Fehler darüber.

Ich versuche, einige andere Dinge, wie ghci Examples.hs -fobject-code verwenden, ghci -lmsvcrt Examples.hs -fobject-code und sogar

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

die in ghc Examples.hs -v5 gefunden wurde.

Leider funktioniert nichts für meine main, und ich kann keinen anderen Weg dafür finden.

P.S. Gibt es jemanden, der weiß, wie man hSetBuffering in Windows verwendet (es wurde vor 8 Jahren in ghc ticket #2189 veröffentlicht. Ist es nicht behoben?)

+0

Ich kann Ihnen zwei Dinge nicht hilfreich nur sagen: 1. Die in Linux funktioniert gut 'stdio.h getchar' verwenden, ohne angeben zu müssen eine Bibliothek, und 2. Ihr Ansatz sieht ungefähr richtig aus. – crockeea

+0

@Eric In Linux ist FFI in diesem Fall nicht nötig, da die hSetBuffering-Funktion gut funktioniert und ich mit dieser Funktion _Bufferless Input_ machen kann. Dieser Ansatz funktionierte jedoch nicht für Windows. –

+0

Ich bezog mich nur auf Ihre Hauptfrage des Versuchens, mit 'getChar zu verbinden. Ich kann Ihnen beim Pufferungsproblem nicht helfen. – crockeea

Antwort

1

Dies ist, weil es keine getch unter Windows gibt. getch ist POSIX und POSIX ist unter Windows veraltet. Es ist immer noch vorhanden, aber die Funktionen wurden in einen anderen Namespace verschoben (um den Root-Namespace für Benutzerprogramme freizugeben). Wie Sie sehen können, lautet MSDN getch ist veraltet https://msdn.microsoft.com/en-us/library/ms235446.aspx und stattdessen _getch verwenden.

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 

Funktioniert sowohl kompiliert als auch interpretiert.

In Bezug auf das, warum es funktioniert kompiliert und nicht interpretiert, wenn getch mit:

Das MingW-w64 Projekt wird nie veraltete Funktionen entfernt, wie Microsoft

Als solche

$ 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 

hat getch umgeleitet wird zu _getch und so haben sie beide Versionen. Dies ist eine Quelle der Inkompatibilität zwischen MSVC++ und GCC.

Microsoft jedoch hat sie entfernt

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

Also, was passiert, wenn Sie einen Link gegen msvcrt:

  1. Im kompilierten Modus sowohl GCC und GHC wird die statische Bibliothek zuerst holen, die passiert werden eine Import-Lib libmsvcrt.dll.a. Dies liegt an der Verknüpfungsreihenfolge des Linkers (ld).

  2. Im interpretierten Modus wird GHCi immer bevorzugen die dynamische Version der Bibliothek über die statische. Der Grund dafür ist, dass während der Neuverknüpfung (was bei der Einführung eines neuen Scopes oder Reloads passieren muss) dynamische Bibliotheken viel schneller sind, da wir intern keine Umsetzungen und Symbolauflösung vornehmen müssen. Es gibt auch Dinge, die wir immer noch nicht richtig unterstützen, wie schwache Symbole oder gebräuchliche Symbole. Aus diesen Gründen bevorzugen wir einfach die dynamische.

  3. GHCi 8.0.1 unterstützt keine Importbibliotheken. Während Sie GHCi zwingen können, die statische Bibliothek zu verwenden (geben Sie einfach den vollständigen Namen an -l, z. B. -llibmsvcr.a) Es wird nicht funktionieren, weil der Laufzeit-Loader nicht weiß, was damit zu tun ist. Dies wird jedoch in dem aktuellen GIT Master unterstützt und wird wahrscheinlich in 8.0.2

+0

Was ist dann die Option '-l' in 'ghci --show-options'? Und das GHCi-Benutzerhandbuch sagte: "Zusätzliche Bibliotheken können in der Befehlszeile mit der normalen Option -llib angegeben werden." [https://downloads.haskell.org/~ghc/latest/docs/html/users_guide/ghci.html#extra-libraries] –

+0

@JunyoungClareJang '-l' wird verwendet, um dem Linker anzuzeigen, dass Sie eine Abhängigkeit davon haben eine Bibliothek. Bibliotheken gibt es in verschiedenen Formen. Sie haben statische Namen, die gewöhnlich mit '.a' Erweiterungen, dynamischen' .dll' oder Import-Bibliotheken '.dll.a',' .a' und .'.lib' verwendet werden. Wenn Sie "-lfoo" angeben, sagen Sie dem Linker, dass Sie die Bibliothek 'foo' brauchen. Wenn Sie die Bibliothek in mehreren Versionen haben, z. libfoo.dll, libfoo.a, libfoo.lib, welche der Linker verwendet, hängt von den verschiedenen Flags und Suchprioritäten ab. Wie ich bereits sagte, wird GHCi derzeit immer die dynamische Version gegenüber allen statischen bevorzugen. – Phyx

+1

Diese funktionieren nicht magisch, wir müssen aktiv Code schreiben, um sie in GHCi zu unterstützen. Einige Funktionen werden daher noch nicht unterstützt, da sie vom Haskell Runtime Loader (RTS) noch nicht unterstützt werden. Wie ich sagte, Unterstützung für mehr wird aktiv hinzugefügt, wie Import Bibliothek Unterstützung in 8.0.2 https://phabricator.haskell.org/D1696 – Phyx