2015-07-02 18 views
13

Próbuję skompilować kod Rust z kodem Haskella. Mam system testowy skonfigurowany z plikiem, Fibonacci.hs z funkcją, która oblicza numery fibonacciego w Haskell i eksportuje funkcję jako fibonacci_hs przez Haskella FFI (jak tutaj: https://github.com/nh2/haskell-from-python, chociaż będę kopiować i wklejać na dole), a następnie wrapper.c zdefiniował funkcje eksportu do wywołania w celu zainicjowania i wyjścia z RTS Haskella.Wywołanie dynamicznie połączonego kodu Haskella z Rust

Kod wygląda następująco:

{- 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(); 
} 

skompilować je poprzez:

ghc -c -dynamic -fPIC Fibonacci.hs

ghc -c -dynamic -fPIC wrapper.c

i I powiązanie obiektów do wspólnej/biblioteki dynamicznej (więcej na ten temat w drugi) poprzez:

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

Na uruchamiając przykładowy kod Pythona z połączonego repozytorium, to działa dobrze na moim Macu, ale mogę Trzeba go połączyć z Rustem.

w Rust mój kod wygląda mniej więcej tak:

//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(); 
    } 
} 

I skompilować z rustc main.rs -L . (od wspólny plik biblioteki jest lokalny).

Błąd wygenerować na Mac, gdy skompilowany z biblioteki dynamicznej (ghc -o libfibonacci.so -shared -static haskell/Fibonacci.o haskell/wrapper.o -lHSrts następnie „rustc main.rs -L.) Jest w czasie wykonywania:

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

Dzięki za pomoc z góry.

+0

Przepraszam za to. @Shepmaster --typo z mojej strony, powinno być .c. – chalkandpaste

+0

@ReidBarton Wycinam wszystkie obce rzeczy. Koncentrując się na kompilacji biblioteki dynamicznej na moim macu przy użyciu Rust i Haskell. – chalkandpaste

Odpowiedz

5

Kiedy skompilować bibliotekę współdzieloną, wygląda na to trzeba połączyć przeciwko libffi także:

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

wywnioskowałem to przechodząc do mojego katalogu biblioteki GHC (/usr/local/lib/ghc-7.10.1/rts), a następnie grepping symbolu ffi_call :

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

I następnie wykorzystywane nm znaleźć których dokładna biblioteka miała go:

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

byłem wtedy w stanie uruchomić z:

DYLD_LIBRARY_PATH='.' ./main 

Niestety, wydaje się, Twój kod nie jest całkiem w porządku, a ja po prostu kilka pustych krotek. Zapomniałeś mieć typ zwrotu na funkcji, a następnie napotkasz problem, że 46-te lub tak Fibbonacci jest zbyt duże dla u32.

Dodatkowo należy używać typów z paczki libc, dlatego może być najbezpieczniej używać tutaj u64.

Zainstalowałem GHC 7.10.1 używając Homebrew, ale mam nadzieję, że ten sam schemat będzie działał gdzie indziej.

+0

Dzięki, człowiek z bandą. Zdarzyło mi się, że ostatniej nocy źle dostałem zwrotu - miałem konstrukcję, która jakoś zadziałała (nie udało mi się odtworzyć dzisiaj) i otrzymałem typ jednostki/puste zwroty krotek, ale nie mogłem zrozumieć, co to pozwoliło budować (nic w mojej historii nie pozwoliło mi się rozmnażać). Jeszcze raz wielkie dzięki @Shepmaster! – chalkandpaste

5

można wspomnieć o dwóch różnych końcowych poleceń linków,

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

i

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

Może warto wyraźnie opisując, co niektóre z tych flag na myśli.

  • -shared mówi GHC produkować wspólny obiekt (zamiast pliku wykonywalnego).

  • -dynamic mówi GHC połączyć wyjście przed dynamicznych wersjach bibliotecznych jego zależnościami Haskell (zasada, ghc-prim, etc.)

  • -static jest przeciwieństwem -dynamic, mówi GHC aby połączyć przeciwko statyczne wersje bibliotek zależności Haskella.

  • -lHSrts oznacza link do bibliotek (statycznych lub udostępnionych) libHSrts. Ale w GHC, tylko biblioteka statyczna rzeczywiście ma bibliotekę baseHSHSHS (tak, że nazwa pliku biblioteki to libHSrts.a). Wersja biblioteki współużytkowanej ma nazwę pliku libHSrts-ghc7.8.4.so (dostosuj do wersji GHC). Tak więc, -lHSrts naprawdę oznacza połączenie z biblioteką statyczną RTS.

Tak więc drugie polecenie łączy się ze statycznymi wersjami wszystkich zależności Haskell, w tym RTS. To może działać na OS X, gdzie cały kod musi być generowany jako PIC, ale nie będzie działał na zwykłej dystrybucji binarnej GHC na Linuksie, ponieważ biblioteka współdzielona musi być kodem PIC, ale statyczne biblioteki Haskella dostarczane z GHC są budowane jako -PIC (są one przeznaczone do łączenia z nierelokowalnymi plikami wykonywanymi). Nie do końca rozumiem, dlaczego GHC nie jest wystarczająco inteligentny, aby dodać tutaj samą -lffi, prawdopodobnie nie spodziewa się takiej kombinacji opcji, ponieważ nie będzie działać na normalnej instalacji Linuksa.

Pierwsze polecenie jest nieparzyste, ponieważ łączysz statycznie z RTS, ale dynamicznie wobec wszystkich innych zależności Haskell. Jeśli zmienisz nazwę biblioteki w opcji -l na -lHSrts-ghc7.8.4, wszystko będzie działać na Linuksie i prawdopodobnie wszędzie (poza Windows).

Powiązane problemy