简体   繁体   English

使用Clojure库捆绑本机JNI共享库

[英]Bundle native JNI shared libraries with Clojure libraries

I am writing a library for clojure which involves native code. 我正在编写一个涉及本机代码的clojure库。 How can I bundle the shared library (aka native dependencies) when I deploy the clojure libraries to public repositories (like clojars)? 当我将clojure库部署到公共存储库(如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. 我目前正在使用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. 但是,如果我将此项目作为依赖项包含,我将收到UnsatisfiedLink错误。

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 your project.clj . 将本机库捆绑在库jar中,例如将native/文件夹包含在project.clj中的:resource-paths中。
  • 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. 当您使用库时,可以指定:native-prefix选项以指示库jar中的路径,应从中提取本机库。 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 ""] 例如,如果您的库在根文件夹中包含资源“mylib.so”,您可以像这样指定它: [com.foo/bar "1.0.1" :native-prefix ""]
  • you should also specify where the extracted libs should go, using the :native-path option in your project.clj . 您还应该使用project.clj:native-path选项指定提取的库应该去的位置。
  • finally, you should add the :native-path you have specified to java.library.path , using :jvm-opts like you said. 最后,你应该使用:jvm-opts将你指定的:native-path添加到java.library.path

These options are documented in the sample leiningen project.clj . 这些选项记录在示例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. 现在我说它取决于你的用例的原因是,如果你想创建一个包含本机库的uberjar,事情开始变得更加混乱。 The main reason is that you can't directly link to a lib that is zipped inside your jar. 主要原因是你无法直接链接到jar中压缩的lib。 If you're lucky, you'll be able to use the loadLibraryFromJar method in the NativeUtils class. 如果幸运的话,您将能够在NativeUtils类中使用loadLibraryFromJar方法。 However, I remember having ClassLoader -related issues that prevented me from using System/load . 但是,我记得有ClassLoader问题导致我无法使用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. 相反,我必须确保库存在于JVM查找的其中一个路径中,以便System/loadLibrary正确地找到它。 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)) 在运行时从uberjar手动提取本机lib到一个临时文件夹,使用(-> 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, using System/setProperty 使用System/setProperty在运行时更新java.library.path系统属性以向其添加临时文件夹
  • 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. 设置很痛苦,但之后效果很好。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM