2012-05-18 24 views
51

Tôi gặp sự cố liên quan đến FFI trong Haskell và chế độ tương tác của GHC again.Vấn đề liên kết thời gian chạy GHCi khi sử dụng khai báo FFI

Cân nhắc FFISo.hs:

{-# LANGUAGE OverloadedStrings #-} 
module Main where 

import qualified Data.ByteString.Char8 as B 

import FFIFun.Foo 

main :: IO() 
main = do 
    B.putStrLn "main" 
    callMeFromC 
    callMeFromHaskell 
    return() 

c.c:

#include <stdio.h> 

void callMeFromC(void); 

void callMeFromHaskell(void) 
{ 
    printf("callMeFromHaskell\n"); 
    callMeFromC(); 
} 

FFIFun/Foo.hs:

{-# LANGUAGE OverloadedStrings #-} 
{-# LANGUAGE ForeignFunctionInterface #-} 
module FFIFun.Foo where 

import qualified Data.ByteString.Char8 as B 

foreign import ccall "callMeFromHaskell" 
    callMeFromHaskell :: IO() 

foreign export ccall callMeFromC :: IO() 
callMeFromC :: IO() 
callMeFromC = B.putStrLn "callMeFromC" 

Makefile:

SHELL := bash 

GHC_OPT := -Wall -O2 -fno-warn-unused-do-bind 


all: ffiso 

test: ffiso 
    ./$< 

ffiso: FFISo.hs c.c 
    ghc --make $(GHC_OPT) $^ -o [email protected] 

clean: 
    rm -rf *{.hi,o,_stub.*} ffiso FFIFun/*{.hi,.o,_stub.*} 

ghci: ffiso 
    ghci -package bytestring FFIFun/Foo.o c.o FFISo.hs 

bạn cũng tìm thấy nó here as a gist.

Vì vậy, vấn đề của tôi bây giờ là:

$ make ghci 
[...] 
Ok, modules loaded: Main, FFIFun.Foo. 
Prelude Main> -- fine, it's loading. 
Prelude Main> :t callMeFromC 

<interactive>:1:1: Not in scope: `callMeFromC' 
Prelude Main> -- uhm, why? 
Prelude Main> :t main 
main :: IO() 
Prelude Main> main 


GHCi runtime linker: fatal error: I found a duplicate definition for symbol 
    FFIFunziFoo_callMeFromC_info 
whilst processing object file 
    ./FFIFun/Foo.o 
This could be caused by: 
    * Loading two different object files which export the same symbol 
    * Specifying the same object file twice on the GHCi command line 
    * An incorrect `package.conf' entry, causing some object to be 
    loaded twice. 
GHCi cannot safely continue in this situation. Exiting now. Sorry. 

Hrmpf, những gì là sai ở đây? Điều thú vị là tôi nhận được một lỗi khác nhau trên i686 (ở trên, đó là một hệ thống x86_64, nhưng cả hai GHC 7.4.1):

GHCi runtime linker: fatal error: I found a duplicate definition for symbol 
    __stginit_FFIFunziFoo 
whilst processing object file 
    ./FFIFun/Foo.o 
This could be caused by: 
    * Loading two different object files which export the same symbol 
    * Specifying the same object file twice on the GHCi command line 
    * An incorrect `package.conf' entry, causing some object to be 
    loaded twice. 
GHCi cannot safely continue in this situation. Exiting now. Sorry. 

Ngoài ra, có một số tài liệu về nó? Tôi cảm thấy mình là người duy nhất gặp khó khăn với FFI và GHCi.

chỉnh sửa: lưu ý, rằng make test hoạt động tốt:

$ ghc --make -Wall -O2 -fno-warn-unused-do-bind FFISo.hs c.c -o ffiso 
[1 of 2] Compiling FFIFun.Foo  (FFIFun/Foo.hs, FFIFun/Foo.o) 
[2 of 2] Compiling Main    (FFISo.hs, FFISo.o) 
Linking ffiso ... 
./ffiso 
main 
callMeFromC 
callMeFromHaskell 
callMeFromC 
+0

Bạn có thể gặp phải các tình huống nếu bạn cố gắng liên kết tĩnh một mô-đun với một biểu tượng FFI; và cũng tự động tải nó. –

+0

bạn có thể xây dựng? hoặc làm cách nào để giải quyết vấn đề này? –

+3

Tôi chơi xung quanh với nó một chút và nó có vẻ là một lỗi trong GHCi. Biểu tượng được xem xét hai lần: Một lần vì nó được tải trên dòng lệnh thông qua tệp .o và một lần vì tệp .hs được tải. Dường như. Có lẽ nó không nên liên kết ở tất cả khi bắt đầu ghci, nhưng chỉ khi thực hiện các công cụ? –

Trả lời

3

Đây là a known limitation các tập tin đối tượng liên kết động trong thông dịch bytecode, GHCi.

Nếu bạn tải mã đã biên dịch được liên kết tĩnh với một đối tượng C đã cho, và sau đó cũng diễn giải một số Haskell trên bay cũng đề cập qua FFI đến cùng một đối tượng C, trình liên kết thời gian chạy sẽ bị buộc tải C đối tượng động.

Bây giờ bạn có hai phiên bản của biểu tượng C trong không gian địa chỉ của bạn và lỗi xảy ra sau đó.

Bạn phải giải thích mọi thứ theo chế độ GHCi hoặc từ bỏ sử dụng GHCi cho quá trình này. Đối với một số trình liên kết hệ điều hành, bạn có thể trưng ra bảng biểu tượng được liên kết tĩnh qua bảng động, (cờ -x).

+0

[Đây là câu trả lời khác của bạn cho câu hỏi tương tự ] (http://stackoverflow.com/a/13398390/439034). Phản ứng tốt đẹp. Mặc dù tôi không thể tìm ra những gì thiết lập cờ '-x' sẽ kéo theo khi làm việc với api GHC và' dynCompileExpr'. Tôi đoán một số giá trị cho 'ghcLink' (trong cuộc gọi đến' setSessionDynFlags') có thể làm điều đó nhưng cho đến nay không có may mắn. Có lẽ cờ cần được đặt cho phiên "cha mẹ". – worldsayshi

Các vấn đề liên quan