2015-07-02 22 views
13

Tôi đang cố gắng biên dịch một số mã Rust với một số mã Haskell. Tôi có một hệ thống thử nghiệm được thiết lập với một tệp, Fibonacci.hs với một hàm tính số lượng mã trong Haskell và xuất hàm theo số fibonacci_hs qua FFI của Haskell (như ở đây: https://github.com/nh2/haskell-from-python, mặc dù tôi sẽ sao chép và dán ở dưới cùng), và wrapper.c đã xác định các chức năng xuất để được gọi để khởi tạo và thoát khỏi RTS của Haskell.Gọi mã Haskell được liên kết động từ Rust

Mã này trông như thế này:

{- Fibonacci.hs -} 
{-# LANGUAGE ForeignFunctionInterface #-} 

module Fibonacci where 

import Foreign.C.Types 

fibonacci :: Int -> Int 
fibonacci n = fibs !! n 
    where fibs = 0 : 1 : zipWith (+) fibs (tail fibs) 

fibonacci_hs :: CInt -> CInt 
fibonacci_hs = fromIntegral . fibonacci . fromIntegral 

foreign export ccall fibonacci_hs :: CInt -> CInt 

// wrapper.c 

#include <stdlib.h> 
#include "HsFFI.h" 

void 
example_init (void) 
{ 
    hs_init (NULL, NULL); 
} 

void 
example_exit (void) 
{ 
    hs_exit(); 
} 

tôi biên soạn những qua:

ghc -c -dynamic -fPIC Fibonacci.hs

ghc -c -dynamic -fPIC wrapper.c

và tôi liên kết các đối tượng vào một chia sẻ thư viện/động (thêm về điều này trong một giây) thông qua:

ghc -o libfibonacci.so -shared -dynamic -fPIC Fibonacci.o wrapper.o -lHSrts

On chạy mã ví dụ Python từ kho lưu trữ liên kết, nó chỉ chạy tốt trên mac của tôi, nhưng tôi có thể không liên kết với Rust.

Trong Rust mã của tôi trông giống như sau:

//main.rs 
#[link(name = "fibonacci")] 
extern { 
    fn fibonacci_hs (n : i32); // c_int = i32 
    fn fib_init(); // start hs rts 
    fn fib_exit(); // kill hs rts 
} 

fn main() { 
    unsafe { 
     fib_init(); 
     for i in 0..100 { 
      println!("{:?}th fibonacci : {:?}", i, fibonacci_hs(i)); 
     } 
     fib_exit(); 
    } 
} 

Và tôi biên dịch với rustc main.rs -L . (kể từ khi chia sẻ tập tin thư viện là địa phương).

Các lỗi tôi tạo ra trên Mac, khi biên soạn với một thư viện động (ghc -o libfibonacci.so -shared -static haskell/Fibonacci.o haskell/wrapper.o -lHSrts rồi 'rustc main.rs -L.) Là tại thời gian chạy:

dyld: Symbol not found: _ffi_call 
    Referenced from: ./libfibonacci.so 
    Expected in: flat namespace 
in ./libfibonacci.so 
Trace/BPT trap: 5 

Nhờ sự giúp đỡ trước.

+0

Xin lỗi về điều đó. @Shepmaster --typo về phía tôi, nên là .c. – chalkandpaste

+0

@ReidBarton Tôi cắt giảm tất cả những thứ không liên quan. Tập trung vào việc biên dịch một thư viện động trên mac của tôi bằng cách sử dụng Rust và Haskell. – chalkandpaste

Trả lời

5

Khi bạn biên dịch thư viện chia sẻ của bạn, có vẻ như bạn cần phải liên kết chống lại libffi cũng như:

ghc -o libfibonacci.dylib -shared -dynamic -fPIC \ 
    Fibonacci.hs wrapper.c -lHSrts -lffi 

tôi suy luận này bằng cách vào thư mục thư viện GHC của tôi (/usr/local/lib/ghc-7.10.1/rts) và sau đó grepping cho biểu tượng ffi_call :

$ grep -lRa ffi_call . 
./include/ffi.h 
./rts/libHSrts-ghc7.10.1.dylib 
... 

tôi sau đó sử dụng nm để tìm mà thư viện chính xác đã có nó:

for i in *dylib; do 
    if nm $i | grep -q 'T.*ffi_call'; then 
     echo "== $i"; 
    fi; 
done 

tôi sau đó có thể chạy với:

DYLD_LIBRARY_PATH='.' ./main 

Thật không may, nó xuất hiện mã của bạn là không hoàn toàn đúng, vì tôi chỉ nhận được một loạt các bộ dữ liệu rỗng. Bạn quên có kiểu trả về trên hàm, và sau đó bạn gặp phải vấn đề là Fibbonacci 46 hay quá lớn đối với một số u32.

Ngoài ra, bạn nên sử dụng các loại từ gói libc và có thể an toàn nhất để sử dụng số u64 tại đây.

Tôi đã cài đặt GHC 7.10.1 bằng Homebrew, nhưng hy vọng cùng một mẫu sẽ hoạt động ở nơi khác.

+0

Cảm ơn một người đàn ông. Tôi nhận ra đêm cuối cùng mà tôi đã nhận được kiểu trả về sai - Tôi đã có một công trình mà bằng cách nào đó đã làm việc (tôi đã không thể tái sản xuất ngày hôm nay) và có đơn vị loại/trả về trống, nhưng không thể hiểu được điều gì đã cho phép để xây dựng (không có gì trong lịch sử thiết bị đầu cuối của tôi cho phép tôi tạo lại). Một lần nữa, cảm ơn nhiều @Shepmaster! – chalkandpaste

5

Bạn đề cập đến hai lệnh liên kết cuối cùng khác nhau,

ghc -o libfibonacci.so -shared -dynamic -fPIC Fibonacci.o wrapper.o -lHSrts 

ghc -o libfibonacci.so -shared -static haskell/Fibonacci.o haskell/wrapper.o -lHSrts 

Nó có thể là giá trị một cách rõ ràng mô tả những gì một số trong những lá cờ có ý nghĩa.

  • -shared yêu cầu ghc tạo một đối tượng được chia sẻ (thay vì thực thi).

  • -dynamic nói GHC để liên kết các đầu ra so với các phiên bản thư viện động phụ thuộc Haskell của nó (cơ sở, GHC-prim vv)

  • -static là đối diện của -dynamic, nó nói với GHC để liên kết chống lại các phiên bản thư viện tĩnh của các phụ thuộc Haskell.

  • -lHSrts có nghĩa là liên kết với libHSrts thư viện (tĩnh hoặc được chia sẻ). Nhưng trong GHC, chỉ thư viện tĩnh thực sự có libHSrts cơ sở (để tên tệp thư viện là libHSrts.a). Phiên bản thư viện được chia sẻ có tên tệp libHSrts-ghc7.8.4.so (điều chỉnh cho phiên bản GHC của bạn). Vì vậy, -lHSrts thực sự có nghĩa là liên kết với phiên bản thư viện tĩnh của RTS.

Vì vậy, lệnh thứ hai liên kết với các phiên bản tĩnh của tất cả các phụ thuộc Haskell, bao gồm RTS. Điều này có thể làm việc trên OS X, nơi tất cả mã phải được tạo ra như PIC, nhưng nó sẽ không hoạt động trên phân phối nhị phân Linux bình thường của GHC vì một thư viện chia sẻ phải là mã PIC, nhưng các thư viện Haskell tĩnh được gửi đi với GHC được xây dựng như không -PIC (chúng được dự định sẽ được liên kết với các tệp thực thi không thể định vị lại). Tôi không hoàn toàn hiểu tại sao GHC không đủ thông minh để thêm -lffi vào đây, có thể nó không thực sự mong đợi sự kết hợp các tùy chọn này vì nó sẽ không hoạt động trên một thiết lập Linux bình thường.

Lệnh đầu tiên là lẻ, vì bạn đang liên kết tĩnh với RTS, nhưng tự động chống lại tất cả các phụ thuộc Haskell khác. Nếu bạn thay đổi tên thư viện trong tùy chọn -l thành -lHSrts-ghc7.8.4 thì mọi thứ sẽ hoạt động trên Linux và có thể ở mọi nơi khác (ngoài Windows).

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