如何将本机库和 JNI 库捆绑到 JAR 中?
有问题的图书馆是东京内阁。
我想要的是将本机库、JNI 库和所有 Java API 类放在一个 JAR 文件中,以避免重新分发带来的麻烦。
似乎有 GitHub 上的尝试,但
- 它不包含实际的本机库,仅包含 JNI图书馆。
- 它似乎特定于 Leiningen 的本机依赖项插件(它不能作为可再发行组件使用)。
问题是,我可以将所有内容捆绑在一个 JAR 中并重新分发吗?如果是,怎么办?
PS:是的,我意识到这可能会对可移植性产生影响。
The library in question is Tokyo Cabinet.
I want is to have the native library, JNI library, and all Java API classes in one JAR file to avoid redistribution headaches.
There seems to be an attempt at this at GitHub, but
- It does not include the actual native library, only JNI library.
- It seems to be specific to Leiningen's native dependencies plugin (it won't work as a redistributable).
The question is, can I bundle everything in one JAR and redistribute it? If yes, how?
P.S.: Yes, I realize it may have portability implications.
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(7)
可以创建一个包含所有依赖项(包括一个或多个平台的本机 JNI 库)的 JAR 文件。基本机制是使用 System.load(File) 加载库,而不是搜索 java.library.path 系统属性的典型 System.loadLibrary(String)。此方法使安装变得更加简单,因为用户不必在其系统上安装 JNI 库,但代价是可能不支持所有平台,因为平台的特定库可能不包含在单个 JAR 文件中。
该过程如下:
我为 jzmq 添加了执行此操作的功能,jzmq 是 ZeroMQ(无耻插件)的 Java 绑定。代码可以在此处。 jzmq 代码使用混合解决方案,因此如果无法加载嵌入式库,代码将恢复为沿 java.library.path 搜索 JNI 库。
It is possible to create a single JAR file with all dependencies including the native JNI libraries for one or more platforms. The basic mechanism is to use System.load(File) to load the library instead of the typical System.loadLibrary(String) which searches the java.library.path system property. This method makes installation much simpler as the user does not have to install the JNI library on his system, at the expense, however, that all platforms might not be supported as the specific library for a platform might not be included in the single JAR file.
The process is as follows:
I added functionality to do this for jzmq, the Java bindings of ZeroMQ (shameless plug). The code can be found here. The jzmq code uses a hybrid solution so that if an embedded library cannot be loaded, the code will revert to searching for the JNI library along the java.library.path.
https://www.adamheinrich.com/blog /2012/12/how-to-load-native-jni-library-from-jar/
是一篇很棒的文章,它解决了我的问题。
就我而言,我有以下用于初始化库的代码:
https://www.adamheinrich.com/blog/2012/12/how-to-load-native-jni-library-from-jar/
is great article, which solves my issue ..
In my case I've got the following code for initialize the library:
查看 One-JAR。它将您的应用程序包装在一个带有专门的类加载器的 jar 文件中,该类加载器可以处理“jars in jars”等内容。
它通过解压原生(JNI)库来处理它们根据需要复制到临时工作文件夹。
(免责声明:我从未使用过 One-JAR,目前也不需要,只是将其添加为书签以备不时之需。)
Take a look at One-JAR. It will wrap your application up in a single jar file with a specialised class loader which handles "jars within jars" among other things.
It handles native (JNI) libraries by unpacking them to a temporary working folder as required.
(Disclaimer: I've never used One-JAR, haven't needed to as yet, just had it bookmarked for a rainy day.)
1) 将本机库作为资源包含到您的 JAR 中。例如使用 Maven 或 Gradle,以及标准项目布局,将原生库放入
main/resources
目录中。2)在与该库相关的Java类的静态初始化程序中,放置如下代码:
1) Include the native library into your JAR as a Resource. E. g. with Maven or Gradle, and the standard project layout, put the native library into
main/resources
directory.2) Somewhere in static initializers of Java classes, related to this library, put the code like the following:
JarClassLoader 是一个类加载器,用于从单个加载器加载类、本机库和资源怪物 JAR 以及来自怪物 JAR 内的 JAR。
JarClassLoader is a class loader to load classes, native libraries and resources from a single monster JAR and from JARs inside the monster JAR.
Kotlin 的解决方案:
build.gradle.dsl
:将 kotlin 运行时 (kotlin-stdlib-1.4.0.jar) 和本机库 (librust_kotlin.dylib) 复制到 JARmain
方法:将库复制到临时文件以使用绝对路径加载它Solution for Kotlin:
build.gradle.dsl
: copy kotlin runtime (kotlin-stdlib-1.4.0.jar) and native library (librust_kotlin.dylib) to JARmain
method: copy library to a temporary file to load it using absolute path您可能必须将本机库解压缩到本地文件系统。据我所知,本地加载的代码会查看文件系统。
这段代码应该可以帮助您开始(我已经有一段时间没有看过它了,它是出于不同的目的,但应该可以解决问题,而且我现在很忙,但如果您有疑问,请发表评论)我会尽快回复)。
You will probably have to unjar the native library to the local file system. As far as I know the bit of code that does the native loading looks at the file system.
This code should help get you started (I haven't looked at it in a while, and it is for a different purpose but should do the trick, and I am pretty busy at the moment, but if you have questions just leave a comment and I'll answer as soon as I can).