2013-07-19 14 views
6

Piszę prostą aplikację w Scala, która używa bazy danych leveldb poprzez bibliotekę leveldbjni. Mój plik build.sbt wygląda następująco:Biblioteka Scala SBT i JNI

name := "Whatever" 

version := "1.0" 

scalaVersion := "2.10.2" 

libraryDependencies ++= Seq(
    "org.iq80.leveldb" % "leveldb-api" % "0.6", 
    "org.fusesource.leveldbjni" % "leveldbjni-all" % "1.7" 
) 

Object jest wtedy odpowiedzialny za stworzenie bazy danych. Niestety, jeśli uruchomię program, otrzymam kolekcję java.lang.UnsatisfiedLinkError podniesioną przez bibliotekę hawtjni, którą leveldbjni wykorzystuje pod maską.

Błąd może być wywołane również łatwo z konsoli scala:

scala> import java.io.File 
scala> import org.iq80.leveldb._ 
scala> import org.fusesource.leveldbjni.JniDBFactory._ 
scala> factory.open(new File("test"), new Options().createIfMissing(true)) 

java.lang.UnsatisfiedLinkError: org.fusesource.leveldbjni.internal.NativeOptions.init()V 
    at org.fusesource.leveldbjni.internal.NativeOptions.init(Native Method) 
    at org.fusesource.leveldbjni.internal.NativeOptions.<clinit>(NativeOptions.java:54) 
    at org.fusesource.leveldbjni.JniDBFactory$OptionsResourceHolder.init(JniDBFactory.java:98) 
    at org.fusesource.leveldbjni.JniDBFactory.open(JniDBFactory.java:167) 
    at .<init>(<console>:15) 
... 
scala> System getProperty "java.io.tmpdir" 
res2: String = /var/folders/1l/wj6yg_wd15sg_gcql001wchm0000gn/T/ 

nie mogę zrozumieć, co się dzieje, ponieważ biblioteka jest uzyskiwanie prawidłowo pobierane z pliku jar, ale to nie jest uzyskiwanie ładowane do niektóre powody.

$ file /var/folders/1l/wj6yg_wd15sg_gcql001wchm0000gn/T/lib* 
/var/folders/1l/wj6yg_wd15sg_gcql001wchm0000gn/T/libleveldbjni-1.7.jnilib: Mach-O universal binary with 2 architectures 
/var/folders/1l/wj6yg_wd15sg_gcql001wchm0000gn/T/libleveldbjni-1.7.jnilib (for architecture x86_64): Mach-O 64-bit dynamically linked shared library x86_64 
/var/folders/1l/wj6yg_wd15sg_gcql001wchm0000gn/T/libleveldbjni-1.7.jnilib (for architecture i386): Mach-O dynamically linked shared library i386 

Myślę, że problem jest prawdopodobnie związane z classloader że SBT zatrudnia, ale nie jestem pewien, ponieważ jestem stosunkowo nowy Scala.

UPDATE

Wciąż nie znaleźliśmy tego, co lub kto jest winowajcą. W każdym razie biblioteka jest rzeczywiście znaleźć i prawidłowo załadowany, ponieważ mogę wykonać następujące polecenia:

scalac> import org.fusesource.leveldbjni.internal.NativeDB 
scalac> NativeDB.LIBRARY.load() 

Błąd jest w jakiś sposób ze względu na funkcję init() że zgodnie z hawtjnidocumentation jest odpowiedzialny za ustawienie wszystkie statyczne pola oznaczone adnotacją jako stałe pola o stałej wartości. Wyjątkiem może być wywołany przez wpisanie:

scalac> import org.fusesource.leveldbjni.internal.NativeOptions 
scalac> new NativeOptions() 
java.lang.UnsatisfiedLinkError: org.fusesource.leveldbjni.internal.NativeOptions.init()V 
    at org.fusesource.leveldbjni.internal.NativeOptions.init(Native Method) 
    at org.fusesource.leveldbjni.internal.NativeOptions.<clinit>(NativeOptions.java:54) 
    at .<init>(<console>:9) 
+0

Jaka jest zawartość właściwości systemowej 'java.library.path'? Czy próbowałeś ustawić tę właściwość na ścieżkę, na której znajdują się wyodrębnione biblioteki? – Beryllium

+0

Tak już wypróbowano, używając wszystkich możliwych opcji konfiguracji. Wciąż ten sam błąd – nopper

+0

Jakie wersje OS/JDK używasz? –

Odpowiedz

2

Najwidoczniej jest znanym problemem, opisanych w tym sbt issue page. Zaimplementowałem, zgodnie z eventsourced documentation, niestandardowe polecenie run-nobootcp, które wykonuje kod bez dodawania biblioteki Scala do boot klasy clas.

To powinno rozwiązać problem.

+0

Na OS X 10.8 z sbt 0.13 i scala 2.10 przez MacPorts, otrzymuję problem pierwotnie opisany. Problem SBT # 358 wskazuje, że problem ten należy naprawić za pomocą sbt 0.13, ale wydaje się, że tak nie jest. Niestandardowe polecenie run-nobootcp również nie działa ... ale po prostu kopiuję i wklejam bez prawdziwego zrozumienia. Co ciekawe, używanie Leveldbjni z projektu Play działa świetnie. –

+0

Obecnie używam scala 2.10 i sbt 0.13 na OSX 10.8.5 bez żadnych problemów, używając zadania 'run-nobootcp'. Czy jesteś pewien, że postępujesz zgodnie z instrukcjami poprawnie? – nopper

+0

Nie jestem wcale pewien, nie, jako Scala noob. leveldbjni _does_ działa dobrze w kontekście aplikacji Play, więc na razie wystarczająco dobrze. –