Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Calling dynamically linked Haskell code from Rust

I'm trying to compile some Rust code with some Haskell code. I have a test system set up with a file, Fibonacci.hs with a function which computes fibonacci numbers in Haskell and exports the function as fibonacci_hs via Haskell's FFI (as here: https://github.com/nh2/haskell-from-python, though I'll copy and paste at the bottom), and in wrapper.c have defined the functions to export to be called for initializing and exiting Haskell's RTS.

The code looks like this:

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

I compile these via:

ghc -c -dynamic -fPIC Fibonacci.hs

ghc -c -dynamic -fPIC wrapper.c

and I link the objects into a shared/dynamic library (more on this in a second) via:

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

On running the Python example code from the linked repository, it runs just fine on my mac, but I can't get it to link with Rust.

In Rust my code looks something like this:

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

And I compile with rustc main.rs -L . (since shared library file is local).

The error I generate on Mac, when compiled with a dynamic library (ghc -o libfibonacci.so -shared -static haskell/Fibonacci.o haskell/wrapper.o -lHSrts then 'rustc main.rs -L . ) is at runtime:

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

Thanks for any help in advance.

like image 550
chalkandpaste Avatar asked Jul 02 '15 23:07

chalkandpaste


1 Answers

When you compile your shared library, it looks like you need to link against libffi as well:

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

I deduced this by going into my GHC library directory (/usr/local/lib/ghc-7.10.1/rts) and then grepping for the symbol ffi_call:

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

I then used nm to find which exact library had it:

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

I was then able to run with:

DYLD_LIBRARY_PATH='.' ./main

Unfortunately, it appears your code isn't quite right, as I just get a bunch of empty tuples. You forgot to have a return type on the function, and then you run into a problem that the 46th or so Fibbonacci is too big for a u32.

Additionally, you should be using the types from the libc package, and it may be safest to use a u64 here.

I have installed GHC 7.10.1 using Homebrew, but hopefully the same pattern would work elsewhere.

like image 63
Shepmaster Avatar answered Oct 23 '22 11:10

Shepmaster