Windows上的Java JNI和依赖库
长话短说:我有一个可执行jar,它调用Windows上的Java JNI和依赖库,java,java-native-interface,java.library.path,Java,Java Native Interface,Java.library.path,长话短说:我有一个可执行jar,它调用jni.dll,它依赖于lib.dll。我得到了一个非常可怕的不满意的链接错误 答案很接近,但根据我的经验,它并没有解决问题。即使在java.library.path中指定了dll所在的文件夹,它也不会工作。我还必须更改WindowsPATH环境变量。事实上,Windows上默认的java.library.path似乎是path 有什么“漂亮”的方法来解决这个问题吗?我想为Windows构建一个安装程序,我想知道如何处理这个问题,这样最终用户就不必做任何手动
jni.dll
,它依赖于lib.dll
。我得到了一个非常可怕的不满意的链接错误
答案很接近,但根据我的经验,它并没有解决问题。即使在java.library.path
中指定了dll所在的文件夹,它也不会工作。我还必须更改WindowsPATH
环境变量。事实上,Windows上默认的java.library.path
似乎是path
有什么“漂亮”的方法来解决这个问题吗?我想为Windows构建一个安装程序,我想知道如何处理这个问题,这样最终用户就不必做任何手动工作
编辑:
我实现了以下内容:应用程序附带了一个名为“native_libs”的文件夹,其中包含所有受支持体系结构的动态库。结构如下:
/
+- native_libs/
+- windows/
| +- x86/
| | +- ...
| +- x64/
| +- ...
|
+- linux/
| +- x86/
| | +- ...
| +- x64/
| +- ...
|
+- libs/
+- ...
在运行时,当应用程序初始化时,会检测到正确的JRE体系结构和系统操作系统,并将正确的库文件复制到libs/文件夹。java.library.path
也在运行时使用常见的hack进行设置。最后,使用本机启动器设置windows的PATH
环境变量
还有改进的余地吗?也许将dll复制到与jar
文件相同的目录中,就不需要设置java.library.path
和path
变量了?我还需要研究使用System.load()
加载dll,这将消除复制文件的需要。java.library.path
指定System.loadLibrary()
查找动态库文件的目录。如果更改代码中的java.library.path
系统属性,则不会产生任何效果。有一些黑客让Java“忘记”初始值并重新评估Java.library.path
系统属性的内容
但是,依赖库不是由Java加载的,而是由Windows加载的。Windows不关心java.library.path
,它只关心path
环境变量。您唯一的选择是为Java进程调整PATH
。例如,如果从批处理文件启动,请在java调用之前更改PATH
环境变量。如果问题是操作系统找不到依赖项库,是否尝试通过System.loadLibrary()加载它
在加载主库之前?最简单的解决方案是在执行时确保所有.dll都在“.”中。将jni.dll所依赖的dll放在“当前工作目录”中,在运行时检查此System.getProperty(“user.dir”)
以了解“当前工作目录”是什么我理解整个概念,我想要的是一种方法来修复我提到的“漂亮”。不幸的是,运行批处理文件并不“漂亮”。你还有别的想法吗?(顺便说一句,当路径中有“.”时,它是否能够找到依赖的dll?因为显然它没有)。是的,我使用了这样一种方法来确保正确的JNI是根据OS/JRE架构加载的,因为您不能在运行的进程中调整环境变量。如果当前目录包含依赖库,则“.”将起作用。我建议使用本机启动器生成器,其中大多数允许您调整本机库路径。至于黑客,我回答的要点是解释为什么这对依赖库不起作用。我赞成澄清所有感兴趣的人的工作方式--“本机启动器生成器”这对谷歌来说是一个完美的术语,谢谢@IngoKegel我同意Windows应该使用%PATH%加载依赖库
。但是在我的场景中,我将包含依赖DLL
的文件夹放入%PATH%中,但仍然找不到DLL。但如果我将依赖DLL放在JDK的bin文件夹中,它就会工作。因此,我的一些团队成员盲目地将所有DLL放入JDK的bin文件夹,我认为这是一个混乱。这里的详细信息:如果你能顺便来看我,我将不胜感激。是否有其他针对此错误的书面说明?比如“找不到依赖库”或者类似的东西?就是这样。我认为我设计了一个相当愚蠢的解决方案,但它是有效的,至少对用户是透明的。一旦我确信它能工作,我将与您共享。您可以尝试使用依赖项漫游器查看缺少哪些库:“使用System预加载”DLL。load()
在Windows上可以工作,除非DLL之间存在循环依赖项。jni.dll
和lib.dll
之间是否存在循环依赖关系?@SamuelAudet不存在循环依赖关系,请检查我下面的评论。@alkar:如果没有任何效果,则有System.load()
会获取dll的完整文件路径。@alkar:另外,发布完整的堆栈跟踪,请。@EJP:在这些方法的javadoc中,没有任何地方说只加载jni库。请看下面的答案:人们实际上是通过在主库之前加载依赖项来使它工作的。@alkar和EJP:是的,它工作。我应该知道,我一直在Windows上使用黑客软件。您的代码可能有其他问题。@SamuelAudet:是的,根据google的说法应该可以工作,一定是我没有通过lib的两个运行时依赖项。dllI需要检查一下。是否确定Windows将始终在“.”中查找dll?是的,这是一个向后兼容性问题: