On Wednesday 17 February 2010 07:06:27 am Marcin Orczyk wrote:
> I'm working on a project that has to interface with OpenCL runtime
> libraries, which means that I need to load shared libraries.
> Whenever I start sbt, the first time I access the library (using console or
> in unit tests) everything works as it should, however the next time I do
> it,
>
> everything crashes with the:
> > java.lang.UnsatisfiedLinkError: Native Library
>
> /home/zero/tools/jocl/JOCL-0.1.1-beta-src/JOCLJNI/lib/linux/libJOCL-linux-x
>86_64.so already loaded in another classloader
> This kills the whole sbt, so when I start it again, the classloader is
> fresh and everything works fine
> .
> Is there a way to force sbt to use the same classloader for everything?
>
> Apparently JVM does not allow the same native library to be referenced from
> two different classloaders and native libraries are unloaded only when the
> classloader is garbage collected - which means we have no guarantees about
> when it happens.
>
> This essentially forces me to restart sbt after each test run or console
> session. I can live with that, but my productivity would be better if I
> could avoid JVM startup delay every time I want to run some tests.
As you imply, you need the native library loaded once per jvm. However, a
native library is associated with the class loader that loadLibrary is called
from, which I assume means that any code that calls that library has to be
loaded from that class loader.
If you are actively developing that code, the only way to reload that code
short of something like JRebel (if it works with code that calls native
libraries) is to drop that class loader and reload it.
If you can put the code that calls the native library in its own project and
develop it separately so that the code never needs to be reloaded, perhaps sbt
could be modified to accept a classpath to load once and make it a parent of
'test', 'run', ... Is this what you meant by "same classloader for
everything"?
'Once' here is a bit loose: you'd actually be restricted to a using single
Scala version and sbt version at a time. That is, no 'reload', '+', '++' or
anything else I'm not thinking of that causes the project definition to be
reloaded.
-Mark
run-like methods (run, run-main, test:run, and test:run-main), set fork to true."> More research
> https://groups.google.com/d/msg/simple-build-tool/KBzk3i2sxQc/P8kpZRlcjFUJ
> seems to imply that forking is not supported in tests; however, from the
> xsbt wiki seems to imply otherwise
> https://github.com/harrah/xsbt/wiki/Forking
> "To enable forking all run-like methods (run, run-main, test:run, and
> test:run-main), set fork to true."
Note that this says all run-like tasks, which means sbt can fork applications.
I see that you were a part of this thread:
The native library handling feature mentioned is in 0.11.0-RC0 if you want to see if that works for you.
-Mark
Sorry I am a little confused between everything. How should I go about trying the new feature in 0.11?
I really do appreciate your help, time and work.
Again, thank you.
> Thank you Mark,
>
> Sorry I am a little confused between everything. How should I go about trying the new feature in 0.11?
I don't know if you mentioned the specific error you get, but I assume it is the standard "already loaded in another classloader" message. If so, put your native library either on the classpath or in the java.library.path system property. sbt should then handle multiple uses automatically by making a temporary copy of the library for each use to get around the restriction.
To get the native library on the classpath, you can either put the native library in the lib/ directory, where sbt will pick it up automatically or explicitly specify the absolute path to it:
unmanagedJars in Compile += file("/path/to/nativelib.so")
or for a native library in a sub directory of your project:
unmanagedJars in Compile <+= baseDirectory(base => base/"native"/"nativelib.so")
> I really do appreciate your help, time and work.
>
> Again, thank you.
No problem.
-Mark
Keep up the great work. If you happen to be at strange loop, please let me buy you a drink :-)
m
Hi,
I'm having trouble getting this to work (using sbt 0.11)
--
val buildSettings = Defaults.defaultSettings ++ Seq (
scalaVersion := "2.9.1",
unmanagedJars in Compile <+= baseDirectory(base => base/"native")
)
-- errors:
build.sbt:1: error: type mismatch;
found : sbt.Project.Initialize[java.io.Serializable]
required: sbt.Project.Initialize[sbt.Task[?]]
Note: java.io.Serializable >: sbt.Task[?], but trait Initialize is
invariant in type T.
You may wish to define T as -T instead. (SLS 4.5)
unmanagedJars in Compile <+= baseDirectory(base => base/"native")