问题 Windows上的Java JNI和依赖库


长话短说:我有一个可执行的jar,可以调用 jni.dll 这取决于 lib.dll。我得到了那么可怕的哦 UnsatisfiedLinkError

这个 答案非常接近,但根据我的经验,它无法解决问题。即使指定了dll所在的文件夹 java.library.path, 不起作用。我必须改变Windows PATH 环境变量也是如此。实际上是默认的 java.library.path 在Windows上似乎是 PATH

有没有“漂亮”的方法来解决这个问题?我想为Windows构建一个安装程序,我想知道如何处理这个问题,以便最终用户不必做任何手动工作。

编辑:

我实现的内容如下:应用程序附带一个名为“native_libs”的文件夹,该文件夹具有适用于所有受支持体系结构的动态库。结构如下:

/
+- native_libs/
   +- windows/
   |  +- x86/
   |  |  +- ...
   |  +- x64/
   |     +- ...
   |
   +- linux/
   |  +- x86/
   |  |  +- ...
   |  +- x64/
   |     +- ...
   |
   +- libs/
      +- ...

在运行时,在应用程序初始化时,会检测到正确的JRE体系结构和系统OS,并将正确的库文件复制到libs /文件夹。该 java.library.path 正在使用常见的hack在运行时设置。最后, PATH Windows的环境变量是使用本机启动器设置的。

还有改进的余地吗?也许将dll复制到与...相同的目录中 jar 文件将否定设置的必要性 java.library.path 和 PATH 变量?我需要调查加载dll的 System.load() 同样,这将否定复制文件的需要。


9650
2017-09-24 14:06


起源

是否有其他东西写入此错误?像“找不到dependend图书馆”或类似的东西? - Jakub Zaverka
确切地说。我认为我设计了一个非常愚蠢的解决方案,但是起作用并且对用户至少是透明的。一旦我确定它有效,我将分享。 - alkar
您可以尝试使用Dependency Walker来查看缺少的库: dependencywalker.com - Jakub Zaverka
使用“预加载”DLL System.load() 除非你的DLL之间存在循环依赖关系,否则它在Windows上有效。是否存在循环依赖关系 jni.dll 和 lib.dll? - Samuel Audet
@SamuelAudet没有循环依赖,请查看下面的评论。 - alkar


答案:


java.library.path 指定目录所在的位置 System.loadLibrary() 查找动态库文件。如果你改变了 java.library.path 你的代码中的系统属性,它不会有任何影响。有些黑客可以让Java“忘记”初始值并重新评估内容 java.library.path 系统属性。

但是,依赖库不是由Java加载的,它是由Windows加载的。 Windows并不关心 java.library.path,它只关心 PATH 环境变量。你唯一的选择是调整 PATH 为您的Java进程。例如,如果从批处理文件启动它,请更改 PATH 在java调用之前的环境变量。


12
2017-09-24 14:23



我理解整个概念,正如我所提到的,我要求的是一种解决这个“漂亮”问题的方法。不幸的是,运行批处理文件并不“漂亮”。你还有其他建议吗? (顺便说一句,当PATH中有“。”时,它应该能够找到依赖的dll吗?因为显然它没有)。是的,我已经使用了这样的黑客来确保根据OS / JRE arch加载正确的JNI - alkar
您无法在正在运行的进程中调整环境变量。 “”如果当前目录包含依赖库,则将起作用。我建议使用本机启动器生成器,其中大多数允许您调整本机库路径。 - Ingo Kegel
至于黑客,我的回答的主要问题是解释为什么这对依赖库不起作用。 - Ingo Kegel
为了澄清整个事情对任何感兴趣的人都有用的方式而言 - “原生发射器发生器”是google的完美术语,谢谢! - alkar
@IngoKegel我同意Windows应该使用%PATH%来加载 dependent library。但在我的场景中,我把包含的文件夹 dependent DLL 进入%PATH%但仍无法找到DLL。 但是如果我将依赖DLL放入JDK的bin文件夹中,它就可以工作。因此,我的一些团队成员盲目地将所有DLL放入JDK的bin文件夹中,我认为这是一团糟。详情如下: stackoverflow.com/questions/29891114/...  感谢您是否可以来。 - smwikipedia


最简单的解决方案是确保所有.dll都在'。'中。当你执行。


1
2017-09-25 01:52



我需要检查一下。你确定Windows总是会看到“。”对于DLL? - alkar
是的,这是一个向后兼容性问题: blogs.msdn.com/b/oldnewthing/archive/2010/11/10/10088566.aspx - Alex Cohn


如果问题是os无法找到依赖库,您是否尝试过通过它加载它 System.loadLibrary() 在加载主库​​之前?


0
2017-09-24 16:52



是的,它没有用。 - alkar
@alkar:如果没什么作用,那就是 System.load() 它采用完整的文件路径到DLL。 - Denis Tulskiy
@alkar:还请发布一个完整的堆栈跟踪。 - Denis Tulskiy
@EJP:这些方法的javadoc中没有任何地方只能加载jni库。看到这样的答案: stackoverflow.com/a/2906862/143585 人们通过在主库之前加载依赖项来实际设法使其工作。 - Denis Tulskiy
@alkar和EJP:是的,它有效。我应该知道,我一直在Windows上使用该黑客。某物 其他 您的代码可能有问题。 - Samuel Audet


把你的jni.dll所依赖的dll放在你的“当前工作目录”中,检查一下 System.getProperty("user.dir") 在运行时了解你的“当前工作目录”是什么


0
2018-01-25 17:53