我正在为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
- 最后,使用反射技巧强制更新库路径