2011-11-01 17 views
19

Questo probabilmente suona come un incubo, ma mi piacerebbe davvero farlo funzionare. Sto usando questo esempio per la maggior parte: Calling C from Haskell e sto cercando di farlo funzionare su Ubuntu.Chiamare Haskell da Java con C tra

sto facendo funzionare questo in Java:

package test; 

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

questo in C dopo aver creato il file .h con 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); 
} 

e poi per riferimento in Haskell (prima 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 

e questo è quello che sto cercando di compilare con:

ghc -c -O Safe.hs

seguito da:

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

e sto ottenendo questo errore:

/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

io non sono un esperto di C con qualsiasi mezzo e non hanno idea di cosa fare di questo. Ho provato a compilare vari modi con -fPIC, ma ho continuato a ottenere lo stesso errore. Qualche idea su cosa potrei fare storto?

Grazie!

+0

Il codice C non deve avviare il runtime Haskell da qualche parte? Penso che avrai bisogno di inserirlo nel codice da qualche parte, sia sul lato C che sul lato Java. –

+0

Hai pensato di utilizzare JNA (https://github.com/twall/jna#readme) anziché JNI? – Landei

+1

Ho risposto a questo qui: http://stackoverflow.com/questions/10370177/communication-between-java-and-haskell/10370902#10370902 –

risposta

3

Anche se ho praticamente risposto a questa domanda qui: Communication between Java and Haskell, poiché questo problema riguarda più l'errore stesso, aggiungerò qui i dettagli per questo. Il problema deriva dal fatto che Haskell non supporta molto bene le librerie condivise, mentre Java le richiede. Buildings plugins as Haskell shared libs ci dà questa intuizione e soluzione:

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/ 

Questa è una soluzione perché ci richiede di conoscere la versione della libreria rts in fase di compilazione.

2

Se il vostro obiettivo è quello di ottenere in realtà qualcosa di fatto (al contrario di giocare solo in giro con JNI) Suggerisco di affrontare questo come un problema giardino varietà RPC e utilizzando uno dei tanti framework/protocolli per esso:

Protocol Buffers from Google

Thrift from Facebook

Avro (well this is mostly a wire protocol)

da ciò che si sta cercando di fare, Thrift potrebbe essere la soluzione migliore in quanto descrive un cl completa stack RPC di ient/server, ma sono abbastanza sicuro che nessuno di loro avrebbe funzionato su un semplice socket.