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

fyq*_*h95 4 java java-native-interface clojure leiningen

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

更多信息:

我的项目结构大致如下:

src/
    native/     - C code , C Object files and compiled shared libs
    java/       - Java stuff
    clojure/    - Clojure stuff
Run Code Online (Sandbox Code Playgroud)

我目前正在使用 leineingen。我试过这样做:

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

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

noz*_*iar 5

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

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

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

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

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

这设置起来很痛苦,但之后它工作得很好。