将本机JNI共享库与Clojure库捆绑在一起 [英] Bundle native JNI shared libraries with Clojure libraries
问题描述
我正在编写一个涉及本地代码的clojure库。
进一步的信息:
$ b如果我将Clojure库部署到公共存储库(如clojars)$ b
我的项目结构大致如下:
src /
native / - C代码,C对象文件和编译的共享库
java / - Java东西
clojure / - Clojure stuff
b $ b
我目前使用leineingen。我已经尝试:
:jvm-opts [〜(str-Djava.library.path = src / native /:
(System / getenv$ LD_LIBRARY_PATH))]
在项目中。但是,如果我将此项目包含为依赖项,我会收到 UnsatisfiedLink
错误。
答案取决于您的确切用例。在最简单的情况下,您需要:
- 在库jar中捆绑本机lib,例如通过包含
project.clj
中的:resource-paths
中的 - 当你使用你的库时,你可以指定一个
:native-prefix
选项,提取。例如,如果您的库在根文件夹中包含资源mylib.so,您可以这样指定:[com.foo/bar1.0.1:native-prefix] c:
- 您还应该使用
:native-path
选项指定提取的lib应该放在哪里:native-path $ c $
- 最后, c>您已指定
java.library.path
,使用:jvm-opts
>
这些选项记录在 sample leiningen project.clj 。
现在我说的原因取决于你的用例,想创建一个包含本地lib的uberjar,事情开始变得更杂乱。主要原因是你不能直接链接到一个在你的jar里面压缩的lib。如果您幸运,您可以使用 loadLibraryFromJar 方法blob / master / NativeUtils.javarel =nofollow> NativeUtils 类。但是,我记得有 ClassLoader
相关的问题,阻止我使用系统/加载
。相反,我不得不确保该库存在于JVM查找的路径之一,因此 System / loadLibrary
找到它正确。这是我最后做的:
- 在运行时将本地lib从uberjar手动提取到临时文件夹,
( - > my-lib io / resource io / input-stream(io / copy my-temp-file))
- c $ c> java.library.path 系统属性在运行时添加临时文件夹到它,使用
System / setProperty
- 最后,使用这种反思
这是很痛苦的设置,但之后,它的工作相当不错。
I am writing a library for clojure which involves native code. How can I bundle the shared library (aka native dependencies) when I deploy the clojure libraries to public repositories (like clojars)?
Further Info:
My project structure looks roughly like:
src/
native/ - C code , C Object files and compiled shared libs
java/ - Java stuff
clojure/ - Clojure stuff
I am currently using leineingen. I have tried doing:
:jvm-opts [~(str "-Djava.library.path=src/native/:"
(System/getenv "$LD_LIBRARY_PATH"))]
It works if I am in the project. However, if I include this project as a dependency, I will get a UnsatisfiedLink
error.
The answer depends on your exact use-case. In the simplest situation, you need to:
- bundle the native lib inside the library jar, for example by including the
native/
folder in:resource-paths
in yourproject.clj
. - when you use your library, you can specify a
:native-prefix
option to indicate a path inside your library jar from which native libraries should be extracted. For example, if your library contains a resource "mylib.so" in the root folder, you can specify it like this:[com.foo/bar "1.0.1" :native-prefix ""]
- you should also specify where the extracted libs should go, using the
:native-path
option in yourproject.clj
. - finally, you should add the
:native-path
you have specified tojava.library.path
, using:jvm-opts
like you said.
These options are documented in the sample leiningen project.clj.
Now the reason I said it depends on your use-case is that if you want to create an uberjar that contains native libs, things start getting more messy. The main reason is that you can't directly link to a lib that is zipped inside your jar. If you're lucky, you'll be able to use the loadLibraryFromJar
method in the NativeUtils class. However, I remember having ClassLoader
-related issues that prevented me from using System/load
. Instead I had to make sure the library was present in one of the paths that the JVM looks for, so that System/loadLibrary
finds it correctly. Here is what I ended up doing:
- manually extract the native lib from the uberjar at runtime to a temporary folder, with
(-> my-lib io/resource io/input-stream (io/copy my-temp-file))
- update the
java.library.path
system property at runtime to add the temporary folder to it, usingSystem/setProperty
- finally, use this reflection trick to force the library path to be updated
This is painful to setup, but after that it works pretty well.
这篇关于将本机JNI共享库与Clojure库捆绑在一起的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!