将本机JNI共享库与Clojure库捆绑在一起



我正在为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中,例如在project.clj中包含:resource-paths中的native/文件夹。
  • 当您使用库时,您可以指定:native-prefix选项来指示库jar中的路径,从该路径中提取本机库。例如,如果您的库包含资源"mylib. exe"。在根目录下,你可以这样指定:[com.foo/bar "1.0.1" :native-prefix ""]
  • 你还应该指定提取的库应该放在哪里,使用project.clj中的:native-path选项。
  • 最后,您应该将您指定的:native-path添加到java.library.path,使用:jvm-opts,如您所说。

这些选项记录在示例leiningen project.clj中。

现在我说这取决于你的用例的原因是,如果你想创建一个包含本地库的uberjar,事情就会变得更加混乱。主要原因是您不能直接链接到压缩在jar中的库。如果幸运的话,您将能够在NativeUtils类中使用loadLibraryFromJar方法。然而,我记得有ClassLoader相关的问题,阻止了我使用System/load。相反,我必须确保库出现在JVM查找的路径之一中,以便System/loadLibrary正确地找到它。下面是我最后做的:

  • 在运行时手动将本机库从uberjar中提取到临时文件夹中,使用(-> my-lib io/resource io/input-stream (io/copy my-temp-file))
  • 在运行时更新java.library.path系统属性以添加临时文件夹,使用System/setProperty
  • 最后,使用反射技巧强制更新库路径
设置起来很痛苦,但之后就运行得很好了。

最新更新