【问题标题】:Bundle native JNI shared libraries with Clojure libraries将原生 JNI 共享库与 Clojure 库捆绑在一起
【发布时间】:2015-10-01 08:21:56
【问题描述】:

我正在为涉及本机代码的 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 错误。

【问题讨论】:

标签: java clojure java-native-interface leiningen


【解决方案1】:

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

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

这些选项记录在sample 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
  • 最后,使用this reflection trick强制更新库路径

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

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2017-05-12
    • 2017-03-22
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2013-10-25
    相关资源
    最近更新 更多