2016-07-09 8 views
3

まず、Windows 10 64bitとHaskell Platform 8.0.1を使用するように指定します。WindowsのGHCIとのHaskell外部関数インタフェース

次のコードを使用して、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> 

は、私はそのような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: 
    [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のために働いていない、と私はこれのために他の方法を見つけることができません。

P.S. WindowsでhSetBufferingを使用する方法を知っている人はいますか(それは8年前にghc ticket #2189に投稿されていましたが修正されていませんか?)

+0

になります。指定しなくても、これはうまく 'stdio.hのgetchar'を使用して、Linuxで動作します。1.を2.あなたのアプローチはほぼ正しいと思われます。 – crockeea

+0

@Eric Linuxの場合、hSetBuffering関数はうまく動作し、その関数を使うことで_Bufferless Input_を作ることができるので、この場合はFFIの必要はありません。しかし、このアプローチはWindowsではうまくいきませんでした。 –

+0

私は 'getChar'とリンクしようとする主な質問のみを指していました。私はバッファリングの問題についてお手伝いできません。 – crockeea

答えて

1

これは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プロジェクトは削除されませんでした

廃止予定の機能を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はしかし、あなたがmsvcrtにリンクする場合、何が起こるか彼らに

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

を削除しました:

  1. コンパイルモードではGCCとGHCの両方があることを起こるどの最初の静的ライブラリを選択しますインポートライブラリlibmsvcrt.dll.a。これは、リンカー(ld)のリンク順によるものです。

  2. 解釈モードでは、GHCiはとなります。常には静的なものよりもライブラリの動的バージョンを優先します。その理由は、再リンク中(新しいスコープを導入したりリロードする際に発生する)であり、内部的に再配置やシンボル解決を行う必要がないため、ダイナミックライブラリの方がはるかに高速です。弱い記号や共通の記号のように私たちがまだ正しくサポートしていないものもあります。そのため、これらの理由から、動的なものを好むだけです。

  3. GHCi 8.0.1はインポートライブラリをサポートしていません。したがって、GHCiに静的ライブラリ(例:-lというフルネームを指定してください。例:-llibmsvcr.a)を強制的に使用することはできますが、実行時ローダーはその処理方法を知らないため動作しません。しかし、これは現在のGITマスターでサポートされており、おそらく私はあなたに2つの役に立たないもの伝えることができます8.0.2

+0

次に、 'ghci --show-options'の' -l 'オプションは何ですか? GHCiのユーザーガイドによると、 "余分なライブラリは、通常の-llibオプションを使ってコマンドラインで指定することができます。" [https://downloads.haskell.org/~ghc/latest/docs/html/users_guide/ghci.html#extra-libraries] –

+0

@JunyoungClareJang '-l'は、あなたが依存していることをリンカーに示すために使用されます図書館。ライブラリはさまざまな形で提供されます。静的ライブラリには、拡張子 '.a'、動的' .dll'、またはインポートライブラリ '.dll.a'、' .a'、.'lib'があります。 '-lfoo'を指定すると、リンカに' foo'というライブラリが必要です。ライブラリが複数のバージョンにある場合など。リンカが使用するlibfoo.dll、libfoo.a、libfoo.libは、さまざまなフラグと検索の優先順位によって異なります。私が前に言ったように、GHCiは現在、静的バージョンよりも常に動的バージョンを好むでしょう。 – Phyx

+1

これらは魔法のように動作しません.GHCiでそれらをサポートするコードを積極的に書く必要があります。したがって、Haskellランタイムローダー(RTS)はそれらをまだサポートしていないため、一部の機能はまだサポートされていません。私が言ったように、もっと多くのサポートが積極的に追加されています。たとえば、8.0.2でのインポートライブラリサポートhttps://phabricator.haskell.org/D1696 – Phyx