2014-06-23 6 views
6

Problem
Nie mogę wczytać i wywołać metod w skompilowanej klasie c do projektu leiningen. Moje podstawowe podejście polega na załadowaniu klasy Java, JavaWrapper.java, która używa JNI do wywoływania niektórych metod natywnych w kodzie rodzimym, wrapper.o, a następnie wywoływania metod za pośrednictwem tej klasy pakowania java.
Wyobrażam sobie, że są problemy z klasą ładującą ładowanie klasy java, która ładuje kod natywny z projektu clojure, ale biorąc pod uwagę, że nie mogę bezpośrednio uzyskać kodu clojure, aby znaleźć plik wrapper.o na ścieżce biblioteki, jestem nie wiem, jak sobie z tym poradzić.Jak załadować i używać natywnego kodu c w projekcie lein?

plik projektu Lein

(defproject lein-native-test "0.1.0-SNAPSHOT" 
... 
:java-source-paths ["java-path"] 
:jvm-opts ["-Djava.library.path=.:./native:/absolute/path/to/native"] ;;not sure what format it wants 
) 

plik clojure metodą głównej
Próbowałem to lekko zmodyfikowany z czterech podejść, wszystko wliczone w kodzie poniżej wraz z odpowiednimi błędu w komentarzach.

(ns lein-native-test.core 
(:import (com.test JavaWrapper))) 
(def -main [] 
;;four things I've tried and their errors 
(clojure.lang.RT.load "/abs/path/to/wrapper.o") ;;could not find file /abs/path/wrapper.o_init.class or wrapper.o.clj 
(clojure.lang.RT.loadLibrary "wrapper.o") ;;UnsatisfiedLinkError no wrapper.o in java library path 
(JavaWrapper/load "/abs/path/to/wrapper.o") ;;UnsatisfiedLinkError com.test.JavaWrapper.setup() 
(assembly-load "/abs/path/to/wrapper.o") ;;unable to resolvesymbol: assembly-load 
) 

kod Java z rodzimych metod, które wykorzystuje JNI, JavaWrapper.java

public class JavaWrapper{ 
    public native void setup(); 
    public static void load(String lib){ System.load(lib);} 
} 

Przed próbuje uzyskać to do pracy z Clojure i Lein Zrobiłem powodzeniem ładować i używać rodzimych metod w wrapper.o przez JavaWrapper i JNI.

prawdopodobnie związane:
jestem też w stanie załadować wrapper.o w JavaWrapper.java poprzez

System.loadLibrary("wrapper.o"); 

muszę używać

System.load("/absolute/path/to/wrapper.o"); 

wersje narzędzi
wersja clojure: 1.5.1
wersja lein: 2.3.4
JDK: 1.7
os: debian7

Lepsze zrozumienie ClassLoaders lub zwłaszcza pracujących prostym przykładzie byłby bardzo przydatny, dzięki.

Odpowiedz

3

Problem wynikał z błędu nazewnictwa w mojej metodzie w nagłówku C i plikach źródłowych wg jni standard. Prawidłowym sposobem użycia jni z clojure jest utworzenie klasy pakowania Java tak, jak to zrobiłem i załadowanie biblioteki dynamicznej za pomocą metody clojure.lang.RT.loadLibrary
Ponieważ nie mogłem znaleźć dobrych przykładów, zrobiłem demo na github

Błędy
1) (clojure.lang.RT.load "/abs/path/to/wrapper.o") ;; nie może znaleźć pliku /abs/path/wrapper.o_init.class lub wrapper.o.CLJ
ten sposób obciążenie nie ma być używany do natywnego kodu, jego oczekując klasy Javy lub plik CLJ

2) (clojure.lang.RT.loadLibrary „wrapper.o”) ;; UnsatisfiedLinkError nie wrapper.o w ścieżce biblioteki java
Clojure jest w stanie znaleźć biblioteki w czasie łącza, stąd UnsatisfiedLinkError --- jest to spowodowane błędem nazewnictwa

  • pierwsza biblioteka powinna być kompilowany jako dynamiczny biblioteka współdzielona, ​​tj. dla kompilatora gcc użyj -shared flag (I faktycznie, ale nie nazwę pliku wyjściowego z rozszerzeniem .so normalnego)
  • Java i tym samym clojure oczekiwać natywna biblioteka być nazwany w bardzo specyficzny sposób: libwrapper.so (lub. jnilib mac lub pliku DLL dla okien, ale zawsze "lib" prefix)

3) (JavaWrapper/ładunku "/abs/path/to/wrapper.o") ;; UnsatisfiedLinkError com.test.JavaWrapper .setup() Tym razem błąd dotyczy metody w obrębie JavaWrapper w pliku lub bibliotece, co oznacza, że ​​przynajmniej znalazł plik. Błąd UnsatisfiedLinkError, który określa określoną metodę w klasie Java, podobnie jak ta, powinien zawsze wynikać z błędu nazewnictwa między zadeklarowaną metodą natywną w pliku Java i tym, co faktycznie znajduje się w źródłowym lub nagłówkowym pliku c.
Uwaga przestrzeni nazw „com.test”
Deklarując metodę JNI w c nazwa metody muszą przestrzegać określonego formatu,
z http://docs.oracle.com/javase/7/docs/technotes/guides/jni/spec/design.html
„dynamiczne łączniki rozwiązać wpisy na podstawie ich nazw. Pochodzący nazwa metody jest łączone z następujących składników:”

  • przedrostek Java_
  • zniekształcone pełni kwalifikowana nazwa klasy
  • podkreślenia (_) separatora
  • zniekształcone nazwą metody
  • do przeciążenia metod natywnych dwa podkreślenia (__), a następnie przez zniekształcone podpisu argumentu

W tym przypadku sposób źródłem pełnego C podpis byłby

void Java_com_test_setup(JNIEnv *env, jobject obj) 


4)(montaż obciążenia „/abs/path/to/wrapper.o”) ;; stanie resolvesymbol: składające obciążenia
ten sposób także nie jest przeznaczona do załadowania kodu macierzystego