Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Calling Haskell from Java with C in between

This probably sounds like a nightmare, but I'd really like to get this working. I am using this example for the most part: Calling C from Haskell and am trying to get this working on ubuntu.

I am running this in java:

package test;

public class JniTest {
    public native int fib(int x);
}

this in c after creating the .h file with javah: (test_JniTest.c)

#include "test_JniTest.h"
#include "Safe_stub.h"

JNIEXPORT jint JNICALL Java_test_JniTest_fib(JNIEnv * e, jobject o, jint f)
{
  return fibonacci_hs(f);
}

and then for reference in haskell (before stub): (Safe.hs)

module Safe 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

and this is what i'm trying to compile it with:

ghc -c -O Safe.hs

followed by:

ghc -shared -o libTest.jnilib -optc-O test_JniTest.c -I/usr/lib/jvm/java-6-sun-1.6.0.26/include -I/usr/lib/jvm/java-6-sun-1.6.0.26/include/linux

and I am getting this error:

/usr/bin/ld: test_JniTest.o: relocation R_X86_64_PC32 against undefined symbol `fibonacci_hs' can not be used when making a shared object; recompile with -fPIC /usr/bin/ld: final link failed: Bad value collect2: ld returned 1 exit status

I am not a c expert by any means and have no idea what to do about this. I tried compiling various ways with -fPIC, but I kept on getting the same error. Any idea what I might be doing wrong?

Thanks!

like image 425
Charles Durham Avatar asked Nov 01 '11 00:11

Charles Durham


2 Answers

Although I've pretty much answered this question here: Communication between Java and Haskell, since this issue is more about the error itself, I will be adding the details for that here. The issue stems from Haskell not supporting shared libraries very well, while Java requires them. Buildings plugins as Haskell shared libs gives us this insight and workaround:

In principle you can use -shared without -dynamic in the link step. That would mean to statically link the rts all the base libraries into your new shared library. This would make a very big, but standalone shared library. However that would require all the static libraries to have been built with -fPIC so that the code is suitable to include into a shared library and we don't do that at the moment.

If we use ldd again to look at the libfoo.so that we've made we will notice that it is missing a dependency on the rts library. This is problem that we've yet to sort out, so for the moment we can just add the dependency ourselves:

$ ghc --make -dynamic -shared -fPIC Foo.hs -o libfoo.so \
 -lHSrts-ghc6.11 -optl-Wl,-rpath,/opt/ghc/lib/ghc-6.11/

This is a workaround because it requires us to know the version of the rts library at build time.

like image 117
Samuel Audet Avatar answered Nov 01 '22 23:11

Samuel Audet


If your goal is to actually get something done (as opposed to just playing around with JNI) I suggest tackling this as a garden variety RPC problem and utilizing one of the many framework/protocols for it:

Protocol Buffers from Google

Thrift from Facebook

Avro (well this is mostly a wire protocol)

From what you are trying to do, Thrift might be your best bet since it describes a full client/server RPC stack but I'm pretty sure any of them would pretty much work over a simple socket.

like image 2
Rafael Ferreira Avatar answered Nov 01 '22 22:11

Rafael Ferreira