【问题标题】:Integrating native system libraries with SBT将本机系统库与 SBT 集成
【发布时间】:2012-06-01 10:25:54
【问题描述】:

将各种 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 中?

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

【问题讨论】:

    标签: scala sbt


    【解决方案1】:

    根据我过去所做的研究,只有两种方法可以加载原生库:修改 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 运行、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 包装器方法的更多详细信息。

    【讨论】:

    • 您能否详细描述一下“修改 java.library.path 和使用 System.loadLibrary(我觉得大多数人都这样做)”?我想使用带有 sbt 的 java 本机库,并想最终制作一个 jar 以供使用,我应该怎么做才能包含 java.library.path,我应该更改 build.sbt,还是应该为此执行某些命令?谢谢。
    【解决方案2】:

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

    [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)
    

    【讨论】:

      【解决方案3】:

      有一个简单的方法。

      假设原生库存放在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"

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 2011-12-01
        • 2010-11-12
        • 2011-05-27
        • 2012-11-06
        • 1970-01-01
        • 2010-09-06
        • 2021-01-06
        相关资源
        最近更新 更多