"UnsatisfiedLinkError: Native Library already loaded in another classloader" in multimodule project

1.7k Views Asked by At

I have a project which uses JOCL library (http://www.jocl.org/) and has multiple modules. When I run "./activator test" from command line, or run "test" command in SBT console I'm getting errors like the following:

[info] Exception encountered when attempting to run a suite with class name: pl.tarsa.sortalgobox.opencl.CpuMergeSortSpec *** ABORTED ***
[info]   java.lang.UnsatisfiedLinkError: Error while loading native library "JOCL_0_1_9-linux-x86_64" with base name "JOCL_0_1_9"
[info] Operating system name: Linux
[info] Architecture         : amd64
[info] Architecture bit size: 64
[info] ---(start of nested stack traces)---
[info] Stack trace from the attempt to load the library as a file:
[info] java.lang.UnsatisfiedLinkError: no JOCL_0_1_9-linux-x86_64 in java.library.path
[info]  at java.lang.ClassLoader.loadLibrary(ClassLoader.java:1865)
[info]  at java.lang.Runtime.loadLibrary0(Runtime.java:870)
[info]  at java.lang.System.loadLibrary(System.java:1122)
[info]  at org.jocl.LibUtils.loadLibrary(LibUtils.java:80)
[info]  at org.jocl.CL.<clinit>(CL.java:47)
[info]  at pl.tarsa.sortalgobox.opencl.common.CLContextDescription$.enumerate(CLContextDescription.scala:44)
[info]  at pl.tarsa.sortalgobox.opencl.common.CLContextsManager$.contextsDescriptions$lzycompute(CLContextsManager.scala:6)
[info]  at pl.tarsa.sortalgobox.opencl.common.CLContextsManager$.contextsDescriptions(CLContextsManager.scala:6)
[info]  at pl.tarsa.sortalgobox.opencl.common.CLContextsManager$.createCpuContext(CLContextsManager.scala:9)
[info]  at pl.tarsa.sortalgobox.opencl.common.CLContextsCache$.cpuContext$lzycompute(CLContextsCache.scala:24)
[info]  at pl.tarsa.sortalgobox.opencl.common.CLContextsCache$.cpuContext(CLContextsCache.scala:24)
[info]  at pl.tarsa.sortalgobox.opencl.common.CLContextsCache$.withCpuContext(CLContextsCache.scala:28)
[info]  at pl.tarsa.sortalgobox.opencl.common.CpuSort.sort(CpuSort.scala:34)
[info]  at pl.tarsa.sortalgobox.opencl.common.CpuSort.sort(CpuSort.scala:32)
[info]  at pl.tarsa.sortalgobox.sorts.SortChecker.forEmptyArray(SortChecker.scala:31)
[info]  at pl.tarsa.sortalgobox.opencl.CpuMergeSortSpec$$anonfun$1$$anonfun$apply$mcV$sp$1.apply$mcV$sp(CpuMergeSortSpec.scala:32)
[info]  at pl.tarsa.sortalgobox.tests.CommonUnitSpecBase.guardedOpenCLTest(CommonUnitSpecBase.scala:40)
[info]  at pl.tarsa.sortalgobox.opencl.CpuMergeSortSpec$$anonfun$1.apply$mcV$sp(CpuMergeSortSpec.scala:31)
[info]  at pl.tarsa.sortalgobox.opencl.CpuMergeSortSpec$$anonfun$1.apply(CpuMergeSortSpec.scala:31)
[info]  at pl.tarsa.sortalgobox.opencl.CpuMergeSortSpec$$anonfun$1.apply(CpuMergeSortSpec.scala:31)
[info]  at org.scalatest.Transformer$$anonfun$apply$1.apply$mcV$sp(Transformer.scala:22)
[info]  at org.scalatest.OutcomeOf$class.outcomeOf(OutcomeOf.scala:85)
[info]  at org.scalatest.OutcomeOf$.outcomeOf(OutcomeOf.scala:104)
[info]  at org.scalatest.Transformer.apply(Transformer.scala:22)
[info]  at org.scalatest.Transformer.apply(Transformer.scala:20)
[info]  at org.scalatest.FlatSpecLike$$anon$1.apply(FlatSpecLike.scala:1647)
[info]  at org.scalamock.scalatest.AbstractMockFactory$$anonfun$withFixture$1.apply(AbstractMockFactory.scala:35)
[info]  at org.scalamock.scalatest.AbstractMockFactory$$anonfun$withFixture$1.apply(AbstractMockFactory.scala:34)
[info]  at org.scalamock.MockFactoryBase$class.withExpectations(MockFactoryBase.scala:41)
[info]  at pl.tarsa.sortalgobox.tests.CommonUnitSpecBase.withExpectations(CommonUnitSpecBase.scala:28)
[info]  at org.scalamock.scalatest.AbstractMockFactory$class.withFixture(AbstractMockFactory.scala:34)
[info]  at pl.tarsa.sortalgobox.tests.CommonUnitSpecBase.withFixture(CommonUnitSpecBase.scala:28)
[info]  at org.scalatest.FlatSpecLike$class.invokeWithFixture$1(FlatSpecLike.scala:1644)
[info]  at org.scalatest.FlatSpecLike$$anonfun$runTest$1.apply(FlatSpecLike.scala:1656)
[info]  at org.scalatest.FlatSpecLike$$anonfun$runTest$1.apply(FlatSpecLike.scala:1656)
[info]  at org.scalatest.SuperEngine.runTestImpl(Engine.scala:306)
[info]  at org.scalatest.FlatSpecLike$class.runTest(FlatSpecLike.scala:1656)
[info]  at org.scalatest.FlatSpec.runTest(FlatSpec.scala:1683)
[info]  at org.scalatest.FlatSpecLike$$anonfun$runTests$1.apply(FlatSpecLike.scala:1714)
[info]  at org.scalatest.FlatSpecLike$$anonfun$runTests$1.apply(FlatSpecLike.scala:1714)
[info]  at org.scalatest.SuperEngine$$anonfun$traverseSubNodes$1$1.apply(Engine.scala:413)
[info]  at org.scalatest.SuperEngine$$anonfun$traverseSubNodes$1$1.apply(Engine.scala:401)
[info]  at scala.collection.immutable.List.foreach(List.scala:381)
[info]  at org.scalatest.SuperEngine.traverseSubNodes$1(Engine.scala:401)
[info]  at org.scalatest.SuperEngine.org$scalatest$SuperEngine$$runTestsInBranch(Engine.scala:390)
[info]  at org.scalatest.SuperEngine$$anonfun$traverseSubNodes$1$1.apply(Engine.scala:427)
[info]  at org.scalatest.SuperEngine$$anonfun$traverseSubNodes$1$1.apply(Engine.scala:401)
[info]  at scala.collection.immutable.List.foreach(List.scala:381)
[info]  at org.scalatest.SuperEngine.traverseSubNodes$1(Engine.scala:401)
[info]  at org.scalatest.SuperEngine.org$scalatest$SuperEngine$$runTestsInBranch(Engine.scala:396)
[info]  at org.scalatest.SuperEngine.runTestsImpl(Engine.scala:483)
[info]  at org.scalatest.FlatSpecLike$class.runTests(FlatSpecLike.scala:1714)
[info]  at org.scalatest.FlatSpec.runTests(FlatSpec.scala:1683)
[info]  at org.scalatest.Suite$class.run(Suite.scala:1424)
[info]  at org.scalatest.FlatSpec.org$scalatest$FlatSpecLike$$super$run(FlatSpec.scala:1683)
[info]  at org.scalatest.FlatSpecLike$$anonfun$run$1.apply(FlatSpecLike.scala:1760)
[info]  at org.scalatest.FlatSpecLike$$anonfun$run$1.apply(FlatSpecLike.scala:1760)
[info]  at org.scalatest.SuperEngine.runImpl(Engine.scala:545)
[info]  at org.scalatest.FlatSpecLike$class.run(FlatSpecLike.scala:1760)
[info]  at org.scalatest.FlatSpec.run(FlatSpec.scala:1683)
[info]  at org.scalatest.tools.Framework.org$scalatest$tools$Framework$$runSuite(Framework.scala:462)
[info]  at org.scalatest.tools.Framework$ScalaTestTask.execute(Framework.scala:671)
[info]  at sbt.TestRunner.runTest$1(TestFramework.scala:76)
[info]  at sbt.TestRunner.run(TestFramework.scala:85)
[info]  at sbt.TestFramework$$anon$2$$anonfun$$init$$1$$anonfun$apply$8.apply(TestFramework.scala:202)
[info]  at sbt.TestFramework$$anon$2$$anonfun$$init$$1$$anonfun$apply$8.apply(TestFramework.scala:202)
[info]  at sbt.TestFramework$.sbt$TestFramework$$withContextLoader(TestFramework.scala:185)
[info]  at sbt.TestFramework$$anon$2$$anonfun$$init$$1.apply(TestFramework.scala:202)
[info]  at sbt.TestFramework$$anon$2$$anonfun$$init$$1.apply(TestFramework.scala:202)
[info]  at sbt.TestFunction.apply(TestFramework.scala:207)
[info]  at sbt.Tests$$anonfun$9.apply(Tests.scala:216)
[info]  at sbt.Tests$$anonfun$9.apply(Tests.scala:216)
[info]  at sbt.std.Transform$$anon$3$$anonfun$apply$2.apply(System.scala:44)
[info]  at sbt.std.Transform$$anon$3$$anonfun$apply$2.apply(System.scala:44)
[info]  at sbt.std.Transform$$anon$4.work(System.scala:63)
[info]  at sbt.Execute$$anonfun$submit$1$$anonfun$apply$1.apply(Execute.scala:226)
[info]  at sbt.Execute$$anonfun$submit$1$$anonfun$apply$1.apply(Execute.scala:226)
[info]  at sbt.ErrorHandling$.wideConvert(ErrorHandling.scala:17)
[info]  at sbt.Execute.work(Execute.scala:235)
[info]  at sbt.Execute$$anonfun$submit$1.apply(Execute.scala:226)
[info]  at sbt.Execute$$anonfun$submit$1.apply(Execute.scala:226)
[info]  at sbt.ConcurrentRestrictions$$anon$4$$anonfun$1.apply(ConcurrentRestrictions.scala:159)
[info]  at sbt.CompletionService$$anon$2.call(CompletionService.scala:28)
[info]  at java.util.concurrent.FutureTask.run(FutureTask.java:266)
[info]  at java.util.concurrent.Executors$RunnableAdapter.call(Executors.java:511)
[info]  at java.util.concurrent.FutureTask.run(FutureTask.java:266)
[info]  at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1142)
[info]  at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:617)
[info]  at java.lang.Thread.run(Thread.java:745)
[info] Stack trace from the attempt to load the library as a resource:
[info] java.lang.UnsatisfiedLinkError: Native Library /tmp/libJOCL_0_1_9-linux-x86_64.so already loaded in another classloader
[info]  at java.lang.ClassLoader.loadLibrary0(ClassLoader.java:1903)
[info]  at java.lang.ClassLoader.loadLibrary(ClassLoader.java:1822)
[info]  at java.lang.Runtime.load0(Runtime.java:809)
[info]  at java.lang.System.load(System.java:1086)
[info]  at org.jocl.LibUtils.loadLibraryResource(LibUtils.java:188)
[info]  at org.jocl.LibUtils.loadLibrary(LibUtils.java:91)
[info]  at org.jocl.CL.<clinit>(CL.java:47)
[info]  at pl.tarsa.sortalgobox.opencl.common.CLContextDescription$.enumerate(CLContextDescription.scala:44)
[info]  at pl.tarsa.sortalgobox.opencl.common.CLContextsManager$.contextsDescriptions$lzycompute(CLContextsManager.scala:6)
[info]  at pl.tarsa.sortalgobox.opencl.common.CLContextsManager$.contextsDescriptions(CLContextsManager.scala:6)
[info]  at pl.tarsa.sortalgobox.opencl.common.CLContextsManager$.createCpuContext(CLContextsManager.scala:9)
[info]  at pl.tarsa.sortalgobox.opencl.common.CLContextsCache$.cpuContext$lzycompute(CLContextsCache.scala:24)
[info]  at pl.tarsa.sortalgobox.opencl.common.CLContextsCache$.cpuContext(CLContextsCache.scala:24)
[info]  at pl.tarsa.sortalgobox.opencl.common.CLContextsCache$.withCpuContext(CLContextsCache.scala:28)
[info]  at pl.tarsa.sortalgobox.opencl.common.CpuSort.sort(CpuSort.scala:34)
[info]  at pl.tarsa.sortalgobox.opencl.common.CpuSort.sort(CpuSort.scala:32)
[info]  at pl.tarsa.sortalgobox.sorts.SortChecker.forEmptyArray(SortChecker.scala:31)
[info]  at pl.tarsa.sortalgobox.opencl.CpuMergeSortSpec$$anonfun$1$$anonfun$apply$mcV$sp$1.apply$mcV$sp(CpuMergeSortSpec.scala:32)
[info]  at pl.tarsa.sortalgobox.tests.CommonUnitSpecBase.guardedOpenCLTest(CommonUnitSpecBase.scala:40)
[info]  at pl.tarsa.sortalgobox.opencl.CpuMergeSortSpec$$anonfun$1.apply$mcV$sp(CpuMergeSortSpec.scala:31)
[info]  at pl.tarsa.sortalgobox.opencl.CpuMergeSortSpec$$anonfun$1.apply(CpuMergeSortSpec.scala:31)
[info]  at pl.tarsa.sortalgobox.opencl.CpuMergeSortSpec$$anonfun$1.apply(CpuMergeSortSpec.scala:31)
[info]  at org.scalatest.Transformer$$anonfun$apply$1.apply$mcV$sp(Transformer.scala:22)
[info]  at org.scalatest.OutcomeOf$class.outcomeOf(OutcomeOf.scala:85)
[info]  at org.scalatest.OutcomeOf$.outcomeOf(OutcomeOf.scala:104)
[info]  at org.scalatest.Transformer.apply(Transformer.scala:22)
[info]  at org.scalatest.Transformer.apply(Transformer.scala:20)
[info]  at org.scalatest.FlatSpecLike$$anon$1.apply(FlatSpecLike.scala:1647)
[info]  at org.scalamock.scalatest.AbstractMockFactory$$anonfun$withFixture$1.apply(AbstractMockFactory.scala:35)
[info]  at org.scalamock.scalatest.AbstractMockFactory$$anonfun$withFixture$1.apply(AbstractMockFactory.scala:34)
[info]  at org.scalamock.MockFactoryBase$class.withExpectations(MockFactoryBase.scala:41)
[info]  at pl.tarsa.sortalgobox.tests.CommonUnitSpecBase.withExpectations(CommonUnitSpecBase.scala:28)
[info]  at org.scalamock.scalatest.AbstractMockFactory$class.withFixture(AbstractMockFactory.scala:34)
[info]  at pl.tarsa.sortalgobox.tests.CommonUnitSpecBase.withFixture(CommonUnitSpecBase.scala:28)
[info]  at org.scalatest.FlatSpecLike$class.invokeWithFixture$1(FlatSpecLike.scala:1644)
[info]  at org.scalatest.FlatSpecLike$$anonfun$runTest$1.apply(FlatSpecLike.scala:1656)
[info]  at org.scalatest.FlatSpecLike$$anonfun$runTest$1.apply(FlatSpecLike.scala:1656)
[info]  at org.scalatest.SuperEngine.runTestImpl(Engine.scala:306)
[info]  at org.scalatest.FlatSpecLike$class.runTest(FlatSpecLike.scala:1656)
[info]  at org.scalatest.FlatSpec.runTest(FlatSpec.scala:1683)
[info]  at org.scalatest.FlatSpecLike$$anonfun$runTests$1.apply(FlatSpecLike.scala:1714)
[info]  at org.scalatest.FlatSpecLike$$anonfun$runTests$1.apply(FlatSpecLike.scala:1714)
[info]  at org.scalatest.SuperEngine$$anonfun$traverseSubNodes$1$1.apply(Engine.scala:413)
[info]  at org.scalatest.SuperEngine$$anonfun$traverseSubNodes$1$1.apply(Engine.scala:401)
[info]  at scala.collection.immutable.List.foreach(List.scala:381)
[info]  at org.scalatest.SuperEngine.traverseSubNodes$1(Engine.scala:401)
[info]  at org.scalatest.SuperEngine.org$scalatest$SuperEngine$$runTestsInBranch(Engine.scala:390)
[info]  at org.scalatest.SuperEngine$$anonfun$traverseSubNodes$1$1.apply(Engine.scala:427)
[info]  at org.scalatest.SuperEngine$$anonfun$traverseSubNodes$1$1.apply(Engine.scala:401)
[info]  at scala.collection.immutable.List.foreach(List.scala:381)
[info]  at org.scalatest.SuperEngine.traverseSubNodes$1(Engine.scala:401)
[info]  at org.scalatest.SuperEngine.org$scalatest$SuperEngine$$runTestsInBranch(Engine.scala:396)
[info]  at org.scalatest.SuperEngine.runTestsImpl(Engine.scala:483)
[info]  at org.scalatest.FlatSpecLike$class.runTests(FlatSpecLike.scala:1714)
[info]  at org.scalatest.FlatSpec.runTests(FlatSpec.scala:1683)
[info]  at org.scalatest.Suite$class.run(Suite.scala:1424)
[info]  at org.scalatest.FlatSpec.org$scalatest$FlatSpecLike$$super$run(FlatSpec.scala:1683)
[info]  at org.scalatest.FlatSpecLike$$anonfun$run$1.apply(FlatSpecLike.scala:1760)
[info]  at org.scalatest.FlatSpecLike$$anonfun$run$1.apply(FlatSpecLike.scala:1760)
[info]  at org.scalatest.SuperEngine.runImpl(Engine.scala:545)
[info]  at org.scalatest.FlatSpecLike$class.run(FlatSpecLike.scala:1760)
[info]  at org.scalatest.FlatSpec.run(FlatSpec.scala:1683)
[info]  at org.scalatest.tools.Framework.org$scalatest$tools$Framework$$runSuite(Framework.scala:462)
[info]  at org.scalatest.tools.Framework$ScalaTestTask.execute(Framework.scala:671)
[info]  at sbt.TestRunner.runTest$1(TestFramework.scala:76)
[info]  at sbt.TestRunner.run(TestFramework.scala:85)
[info]  at sbt.TestFramework$$anon$2$$anonfun$$init$$1$$anonfun$apply$8.apply(TestFramework.scala:202)
[info]  at sbt.TestFramework$$anon$2$$anonfun$$init$$1$$anonfun$apply$8.apply(TestFramework.scala:202)
[info]  at sbt.TestFramework$.sbt$TestFramework$$withContextLoader(TestFramework.scala:185)
[info]  at sbt.TestFramework$$anon$2$$anonfun$$init$$1.apply(TestFramework.scala:202)
[info]  at sbt.TestFramework$$anon$2$$anonfun$$init$$1.apply(TestFramework.scala:202)
[info]  at sbt.TestFunction.apply(TestFramework.scala:207)
[info]  at sbt.Tests$$anonfun$9.apply(Tests.scala:216)
[info]  at sbt.Tests$$anonfun$9.apply(Tests.scala:216)
[info]  at sbt.std.Transform$$anon$3$$anonfun$apply$2.apply(System.scala:44)
[info]  at sbt.std.Transform$$anon$3$$anonfun$apply$2.apply(System.scala:44)
[info]  at sbt.std.Transform$$anon$4.work(System.scala:63)
[info]  at sbt.Execute$$anonfun$submit$1$$anonfun$apply$1.apply(Execute.scala:226)
[info]  at sbt.Execute$$anonfun$submit$1$$anonfun$apply$1.apply(Execute.scala:226)
[info]  at sbt.ErrorHandling$.wideConvert(ErrorHandling.scala:17)
[info]  at sbt.Execute.work(Execute.scala:235)
[info]  at sbt.Execute$$anonfun$submit$1.apply(Execute.scala:226)
[info]  at sbt.Execute$$anonfun$submit$1.apply(Execute.scala:226)
[info]  at sbt.ConcurrentRestrictions$$anon$4$$anonfun$1.apply(ConcurrentRestrictions.scala:159)
[info]  at sbt.CompletionService$$anon$2.call(CompletionService.scala:28)
[info]  at java.util.concurrent.FutureTask.run(FutureTask.java:266)
[info]  at java.util.concurrent.Executors$RunnableAdapter.call(Executors.java:511)
[info]  at java.util.concurrent.FutureTask.run(FutureTask.java:266)
[info]  at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1142)
[info]  at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:617)
[info]  at java.lang.Thread.run(Thread.java:745)
[info] ---(end of nested stack traces)---
[info]   at org.jocl.LibUtils.loadLibrary(LibUtils.java:122)
[info]   at org.jocl.CL.<clinit>(CL.java:47)
[info]   at pl.tarsa.sortalgobox.opencl.common.CLContextDescription$.enumerate(CLContextDescription.scala:44)
[info]   at pl.tarsa.sortalgobox.opencl.common.CLContextsManager$.contextsDescriptions$lzycompute(CLContextsManager.scala:6)
[info]   at pl.tarsa.sortalgobox.opencl.common.CLContextsManager$.contextsDescriptions(CLContextsManager.scala:6)
[info]   at pl.tarsa.sortalgobox.opencl.common.CLContextsManager$.createCpuContext(CLContextsManager.scala:9)
[info]   at pl.tarsa.sortalgobox.opencl.common.CLContextsCache$.cpuContext$lzycompute(CLContextsCache.scala:24)
[info]   at pl.tarsa.sortalgobox.opencl.common.CLContextsCache$.cpuContext(CLContextsCache.scala:24)
[info]   at pl.tarsa.sortalgobox.opencl.common.CLContextsCache$.withCpuContext(CLContextsCache.scala:28)
[info]   at pl.tarsa.sortalgobox.opencl.common.CpuSort.sort(CpuSort.scala:34)

Those errors don't appear for tests in first module/ subproject depending on JOCL. Ie when I do "./activator test" then OpenCL tests from some (first tested) module work and all other don't. When I do "./activator" to spawn SBT console and then run "test" multiple times then for the first time it behaves like ordinary "./activator test" but for next test runs all OpenCL tests fails with UnsatisfiedLinkError.

Here's my build file: https://github.com/tarsa/SortAlgoBox/blob/4a041d93beb572a6dcce100780bc675d46d814f3/project/MainBuild.scala

According to this answer: https://stackoverflow.com/a/23157190/492749 SBT uses some magic classloaders and renames native libraries for each such classloader. The problem is that JOCL unpacks the native libraries during loading of some Java class and the resulting filename and location is always the same. In other words: SBT's magic doesn't play well with JOCL magic.

What would be your solution?

PS: tests work well when executed from within IntelliJ IDEA - probably IDEA doesn't use the classloader magic.

1

There are 1 best solutions below

0
On

According to this answer: https://stackoverflow.com/a/23157190/492749 SBT uses some magic classloaders and renames native libraries for each such classloader. The problem is that JOCL unpacks the native libraries during loading of some Java class and the resulting filename and location is always the same. In other words: SBT's magic doesn't play well with JOCL magic.

This didn't happen automatically for me; I think it's only used when loading SBT plugins. I had to adapt the SBT classloader:

// adapted from sbt.classpath.NativeCopyLoader
package scalan.compilation.lms

import java.io.File
import java.net.{URLClassLoader, URL}
import java.nio.file.Files

/**
 * Loads native libraries from a temporary location in order to work around the jvm native library uniqueness restriction.
 *
 * The loader will provide native libraries listed in `explicitLibraries` and on `searchPaths` by copying them to `tempDirectory`.
 */
class NativeCopyLoader(explicitLibraries: Seq[File], searchPaths: Seq[File], urls: Array[URL], parent: ClassLoader) extends URLClassLoader(urls, parent) {
  private[this] val mapped = new collection.mutable.HashMap[String, String]
  private[this] val tempDirectory = Files.createTempDirectory("native-library-copies").toFile
  tempDirectory.deleteOnExit()

  override protected def findLibrary(name: String): String =
    synchronized { mapped.getOrElseUpdate(name, findLibrary0(name)) }

  private[this] def findLibrary0(name: String): String = {
    val mappedName = System.mapLibraryName(name)
    val explicit = explicitLibraries.filter(_.getName == mappedName).toStream
    val search = searchPaths.toStream flatMap relativeLibrary(mappedName)
    (explicit ++ search).headOption.map(copy).orNull
  }
  private[this] def relativeLibrary(mappedName: String)(base: File): Seq[File] = {
    val f = new File(base, mappedName)
    if (f.isFile) f :: Nil else Nil
  }
  private[this] def copy(f: File): String = {
    val target = new File(tempDirectory, f.getName)
    Files.copy(f.toPath, target.toPath)
    target.getAbsolutePath
  }
}

And then make sure it's used when loading the classes which load the native libraries. This may need modification to work with JOCL magic, however.