Reputation: 1707
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!
Upvotes: 18
Views: 958
Reputation: 4994
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.
Upvotes: 3
Reputation: 1288
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:
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.
Upvotes: 2