31

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

  1. 是否有推荐的方法在run任务中包含本机库?SBT 邮件列表上的讨论表明了以下可能性:

    最后一种的优点是run不需要fork,缺点是必须在SBT之外进行配置。

  2. 我可以在sbteclipse插件生成的 Eclipse 项目中自动包含本机库吗?可以在后处理步骤中重写文件。.project有示例代码吗?有没有更好的办法?

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

我假设本机库没有直接的 SBT 设置。如果存在类似的东西,上述任务能否透明地处理本机库?

4

3 回答 3

30

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

正如您所提到的,java.library.path在配置 SBT 和 Eclipse 方面弄乱可能很烦人,而且我认为不可能自动为可执行 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 运行、Eclipse 和可执行 jar,无需任何额外配置(尽管我不知道 proguard 如何知道要包含哪些资源)。

现在对于已经编写好的第三方原生库,其中一些像jblas已经使用了这种“fat jar”方法。如果他们希望您进行设置java.library.path,然后System.loadLibrary在他们喜欢的时候打电话给他们,那么您需要做一些魔术来完成这项工作。

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

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

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

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

于 2012-05-27T19:32:10.507 回答
0

有一个简单的方法。

假设原生库存储在lib_extra目录中

  1. 将 jna 添加到 libraryDependencies:

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

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

    编译中的 unmanagedResourceDirectories += baseDirectory.value / "lib_extra"

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

于 2016-11-29T08:12:34.143 回答
0

在 Osx 下,如果/lib/*.jnilibsbt 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)
于 2016-07-29T09:13:24.233 回答