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

4

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


你是如何将本地库项目添加到其他项目的依赖项中的? - tnoda
我使用了lein的checkout依赖项 https://github.com/technomancy/leiningen/blob/master/doc/TUTORIAL.md#checkout-dependencies - fyquah95
1个回答

5
答案取决于您的确切用例。在最简单的情况下,您需要:
  • 在库jar包中捆绑本机库,例如通过在project.clj中包含:resource-paths中的native/文件夹。
  • 当您使用库时,可以指定:native-prefix选项,以指示应从其中提取本机库的库jar包内的路径。例如,如果您的库在根文件夹中包含资源"mylib.so",则可以像这样指定它:[com.foo/bar "1.0.1" :native-prefix ""]
  • 您还应该在project.clj中使用:native-path选项指定提取的库的位置。
  • 最后,您应该像您所说的那样使用:jvm-opts将您指定的:native-path添加到java.library.path中。
这些选项在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
  • 最后,使用这个反射技巧强制更新库路径

这很麻烦,但之后它的工作效果相当不错。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接