使用Clojure库捆绑本机JNI共享库

时间:2015-10-01 08:21:56

标签: java clojure java-native-interface leiningen

我正在编写一个涉及本机代码的clojure库。当我将clojure库部署到公共存储库(如clojars)时,如何捆绑共享库(也称为本机依赖项)?

更多信息:

我的项目结构大致如下:

src/
    native/     - C code , C Object files and compiled shared libs
    java/       - Java stuff
    clojure/    - Clojure stuff

我目前正在使用leineingen。我试过了:

:jvm-opts [~(str "-Djava.library.path=src/native/:"
          (System/getenv "$LD_LIBRARY_PATH"))]

如果我在项目中,它会起作用。但是,如果我将此项目作为依赖项包含在内,我将收到UnsatisfiedLink错误。

1 个答案:

答案 0 :(得分:4)

答案取决于您的确切用例。在最简单的情况下,您需要:

  • 将本机库捆绑在库jar中,例如将native/文件夹包含在:resource-paths的{​​{1}}中。
  • 使用库时,可以指定project.clj选项以指示库jar中的路径,应从中提取本机库。例如,如果您的库在根文件夹中包含资源“mylib.so”,则可以这样指定::native-prefix
  • 您还应使用[com.foo/bar "1.0.1" :native-prefix ""]中的:native-path选项指定提取的目标应该去的位置。
  • 最后,您应该使用您所说的project.clj将您指定的:native-path添加到java.library.path

这些选项记录在sample leiningen project.clj

现在我说它取决于你的用例的原因是,如果你想创建一个包含本机库的uberjar,事情开始变得更加混乱。主要原因是你无法直接链接到jar中压缩的lib。如果您很幸运,您将能够使用NativeUtils课程中的:jvm-opts方法。但是,我记得有loadLibraryFromJar个相关问题导致我无法使用ClassLoader。相反,我必须确保库存在于JVM查找的其中一个路径中,以便System/load正确找到它。这是我最终做的事情:

  • 在运行时从uberjar手动提取本机lib到System/loadLibrary
  • 的临时文件夹
  • 使用(-> my-lib io/resource io/input-stream (io/copy my-temp-file))
  • 在运行时更新java.library.path系统属性以向其添加临时文件夹
  • 最后,使用this reflection trick强制更新库路径

设置很痛苦,但之后效果很好。