将本机系统库与SBT集成

时间:2012-05-25 20:48:42

标签: scala sbt

将各种SBT任务与本机库(例如,来自JOGLLWGLJCuda的任务相结合的好方法是什么?具体来说,

  1. 是否建议在run任务中包含本机库?关于SBT邮件列表的讨论表明了这些可能性:

    最后一个的优点是run不需要fork,但缺点是配置必须在SBT之外完成。

  2. 我可以自动在sbteclipse插件生成的Eclipse项目中包含本机库吗?有可能rewrite the .project file in a post-processing step.是否有示例代码?有更好的方法吗?

  3. 本地库是否可以包含在由sbt-assemblysbt-onejarsbt-proguard等插件生成的可运行Jar中?

  4. 我假设本机库没有直接的SBT设置。如果存在这样的事情,上述任务是否可以透明地处理本地库?

3 个答案:

答案 0 :(得分:28)

根据我过去所做的研究,只有两种方法可以加载本机库:修改java.library.path和使用System.loadLibrary(我觉得大多数人这样做),或使用System.load有绝对路径。

正如您所提到的,在配置SBT和Eclipse方面,弄乱java.library.path可能会很烦人,我认为不可能自动执行可执行jar。

离开System.load。在编写自己的本机库方面,您可以做的是:

  • 创建一个SBT任务,用于编译本机源(使用javahgcc),获取生成的.so文件及其依赖的任何.so文件,将它们放入jar中(作为资源) )在目标目录中,将jar的路径添加到unmanagedJars in Compile
  • 创建Scala方法以加载库。它不是调用System.loadLibrary,而是使用Class.getResourceAsStream来读取库,File.createTempFile将其写入文件系统的某个位置,而System.load将其加载到JVM中。
  • 现在,不要像以前那样致电System.loadLibrary,而是致电MyClasspathJniLoader.loadLibrary

这将适用于SBT run,Eclipse和可执行jar,无需任何额外配置(尽管我不知道proguard如何知道要包含哪些资源)。

现在,对于已经编写过的第三方本机库,其中一些像jblas已经使用了这种“胖罐”方法。如果他们希望您设置java.library.path,然后在他们感觉到时调用System.loadLibrary,那么您需要做一些魔术才能实现这一目标。

我没试过这个,但这个解决方案可能有效:

  • 使用类似的SBT任务将其本机路径上的所有库作为资源放入jar中,并将该jar放在clsaspath上。
  • 创建一个Scala方法,它接受一个函数和一个库名列表,创建一个临时目录,从jar资源中将这些库读入temp目录中的文件,将临时目录添加到java.library.path,调用在函数中传递,最后将java.library.path恢复为以前的状态。
  • 第一次调用本机库(当它可能会静态初始化并进行System.loadLibrary调用时),使用它将加载的库列表将该特定调用包装在您的方法中。这样,当它调用System.loadLibrary时,它的所有库都将在java.library.path上,并且将成功加载。

显然这很烦人,因为你必须在使用之前手动初始化第三方库,但是包装所有初始化点(主要功能和测试初始化​​)似乎比获取所有工具更可行正确设置java.library.path。如果您已经在第三方库之上拥有自己的抽象层,那么它可能比这更容易,因此实际上只需要包装一个初始化点。

如果这看起来像是一个现实的解决方案,如果您感到困惑,我可以添加有关SBT任务或Scala包装器方法的更多详细信息。

答案 1 :(得分:0)

在Osx下,如果您在/lib/*.jnilib期间在sbt test中加载本机库时遇到问题。

[error] java.lang.UnsatisfiedLinkError: Fatal execution error, caused by no jniortools in java.library.path

您可以使用以下代码代替System.loadLibrary("jniortools")

new File("lib").listFiles().map(_.getAbsolutePath).filter(_.endsWith("jniortools.jnilib")).foreach(System.load)

答案 2 :(得分:0)

有一种简单的方法。

假设存储在 lib_extra 目录

中的本机库
  1. 将jna添加到libraryDependencies:

      

    libraryDependencies ++ = Seq(" net.java.dev.jna"%" jna-platform"%   " 4.1.0&#34)

  2. 将这些代码添加到build.sbt:

      

    unileagedResourceDirectories in Compile + = baseDirectory.value /" lib_extra"

         

    includeFilter in(Compile,unmanagedResourceDirectories):=" .dll, .so"