2016-07-09 10 views
3

우선 Windows 10 64 비트 및 하스켈 플랫폼 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 ... 

으로 잘 컴파일 할 수 있으며 완전히 실행됩니다. (내가 그것을 실행 후 1을 입력하면)

> Examples.exe 
'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-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에서 발견되었다.

슬프게도, 아무 것도 내 main에 대해 작동하지 않으며 어떤 이유로도 찾을 수 없습니다.

P. Windows에서 hSetBuffering을 사용하는 방법을 알고있는 사람이 있습니까 (8 년 전 ghc ticket #2189에 게시되었습니다.)

+0

에있을 것입니다 : 지정할 필요없이이 잘'stdio.h에 getchar'를 사용하여 리눅스에서 작동 1. 도서관, 그리고 2. 귀하의 접근 방식은 대략 정확합니다. – crockeea

+0

@Eric 리눅스에서는 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 프로젝트는 제거되지 않았다

사용되지 않는 기능을 마이크로 소프트가 리디렉션되는 등

$ 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 사이의 비 호환성의 원인입니다.

컴파일 모드에서
  1. GCC와 GHC 둘 다 될 일이있는 최초의 정적 라이브러리를 선택합니다

    Microsoft는 그러나 당신이 msvcrt에 대한 링크 그래서 무슨 일이 그들에게

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

    을 제거했습니다 가져 오기 라이브러리 libmsvcrt.dll.a. 이것은 링커 (ld)의 링크 순서 때문입니다.

  2. 해석 모드에서 GHCi는 항상 입니다.은 정적 버전보다 라이브러리의 동적 버전을 선호합니다. 그 이유는 재 연결하는 동안 (새로운 범위를 도입하거나 다시로드 할 때 발생합니다) 동적 라이브러리는 내부적으로 재배치 및 심볼 해석을 수행 할 필요가 없기 때문에 훨씬 빠릅니다. 약한 기호 나 일반적인 기호처럼 우리가 여전히 제대로 지원하지 않는 것들도 있습니다. 따라서 이러한 이유로 우리는 동적 인 것을 선호합니다.

  3. GHCi 8.0.1은 가져 오기 라이브러리를 지원하지 않습니다. 그래서 GHCi가 정적 라이브러리 (예 : -l에 전체 이름을 지정하십시오. 예 : -llibmsvcr.a)를 사용하도록 강제 할 수는 있지만 런타임 로더는 어떻게해야 할 지 모르기 때문에 작동하지 않습니다. 그러나 이것은 현재 GIT 마스터에서 지원 가능성 난 단지 당신이 도움이되지 않는 것을 알 수 있습니다 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