问题
I am writing a simple app in Scala
that uses a leveldb database through the leveldbjni
library. My build.sbt
file looks like this:
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"
)
An Object
is then responsible for creating a database. Unfortunately if I run the program I get back a java.lang.UnsatisfiedLinkError
, raised by the hawtjni
library that leveldbjni
exploits under the hood.
The error can be triggered easily also from the scala console:
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/
I can't understand what is going on since the library is getting correctly extracted from the jar file but it is not getting loaded for some reasons.
$ 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
I think the problem is probably related to the classloader that sbt employs but I am not sure since I am relatively new to scala.
UPDATE
Still didn't find what or who is the culprit. Anyway the library is actually found and correctly loaded, since I can execute the following commands:
scalac> import org.fusesource.leveldbjni.internal.NativeDB
scalac> NativeDB.LIBRARY.load()
The error is somehow due to the init()
function that according to the hawtjni
documentation is responsible for setting all the static fields annotated as constant fields with the constant value. The exception can still be triggered by typing:
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)
回答1:
Apparently this is a known problem as documented in this sbt issue page. I have implemented, according to the eventsourced documentation, a custom run-nobootcp
command that executes the code without adding the Scala library to the boot classpath.
This should solve the problem.
来源:https://stackoverflow.com/questions/17750780/scala-sbt-and-jni-library