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

我正在为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错误。

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

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

这些选项记录在样本leiningen project.clj中 。

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

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

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