如何修复JNI项目中的UnsatisfiedLinkError(找不到依赖库)


85

我正在使用JNI的Java项目中。JNI调用了一个我自己编写的自定义库,比方说mylib.dll,它依赖于一个第三方库libsndfile-1.dll。

当我运行程序时,它崩溃

java.lang.UnsatisfiedLinkError:  C:\...path...\mylib.dll: Can't find dependent libraries.

我已经搜索了该网站(和其他网站),并且尝试了许多修复程序:

  1. 我跑了依赖沃克。DW发出了一些警告-libsndfile所需的两个库MPR.DLL和SHLWAPI.DLL具有“未解决的导入”-但DW FAQ表示可以安全地忽略这些警告。

  2. 我已按照此处的建议将方法名称固定在mylib.dll中。方法名称已经被编译器弄乱了,但是我添加了链接器标志,并且dll方法名称现在与我的jni头文件中的名称完全匹配。

  3. 我将所有这些DLL放在相同的目录中-与调用它们的.jar相同的目录中-以确保它们在正确的PATH上。

没有骰子。

有人知道发生了什么吗?

我正在使用MacBook Pro(通过Parallels)在Visual Studio 2010中进行开发。我正在使用东芝笔记本电脑在Windows XP中进行测试。


1
你设置了-Djava.library.path吗?
Jochen Bedersdorfer

实际上,我还没有,因为我没有从命令行启动程序。我正在编写用于Processing的库(processing.org),Processing负责启动我的代码。我已经在运行时检查了Java库路径,并且包含我的DLL的文件夹就在上面。
分贝

正如我所说,所有DLL都位于我的.jar文件旁边的同一文件夹中。因此,我认为问题不在于他们不在路上。但是还是谢谢你。
分贝

7
在Windows上,我们必须将.dll文件放在[JRE] \ bin目录(位于java.exe等的同一位置)中,以使Java自动查看它们,而不必使用命令行选项或环境变量。
QuantumMechanic 2011年

4
嗯...好吧,我尝试将所有.dll放入[JRE] \ bin。这可行!
dB”

Answers:


52

我敢肯定,类路径和共享库搜索路径之间没有任何关系。根据《 JNI书》(公认的是旧的),在Windows上,如果不使用java.library.pathsystem属性,则DLL必须位于当前工作目录中或WindowsPATH环境变量中列出的目录中。


更新:

看起来Oracle已从其网站上删除了PDF。我已经更新了上面的链接,以指向居住在德克萨斯大学阿灵顿分校的PDF实例。

另外,您还可以阅读Oracle的JNI Specification的HTML版本。它位于Java网站的Java 8部分中,因此希望会出现一段时间。


更新2:

至少在Java 8中(我没有检查早期版本),您可以执行以下操作:

java -XshowSettings:properties -version

查找共享库搜索路径。java.library.path在该输出中查找属性的值。


2
是的,CLASSPATH根本不使用。我也不知道cwd完全使用了。java.library.path或只是PATH可以工作。@dB',您现在拥有它们的地方是错误的
欧内斯特·弗里德曼·希尔

非常感谢你们!我认为部分问题是Windows PATH环境变量java.library.path和Java CLASSPATH之间的混淆。现在,这一切都变得更加有意义。
dB”

请您能解释一下您是如何克服这个问题的?
SL_User 2012年

5
@SL_User我认为,如果将库所在的目录添加到环境变量“ path”,然后重新启动命令提示符或终端,则应该对其进行修复。Java在类路径下查找jar,在路径下查找库。
xxjjnn

1
根据此答案,似乎至少从Java 7起就可以使用Update 2的命令了:stackoverflow.com/a/8472139/901641
ArtOfWarfare

18

我想告知这个有趣的情况,在尝试了上述所有方法之后,错误仍然存​​在。奇怪的是,它可以在Windows 7计算机上运行,​​但在Windows XP上则不能。然后,我使用依赖项遍历,发现在Windows XP上没有VC ++ Runtime作为我的dll要求。在这里安装VC ++ Runtime程序包后它就像一个魅力。让我感到困扰的是,它一直在告诉“找不到依赖库”,而直观地存在JNI依赖dll,但是最后发现JNI依赖dll需要另一个依赖dl。我希望这有帮助。


4
该消息是正确的,尽管在这种情况下会引起误解。我在测试盒上缺少VC ++运行时,在调试模式下编译了库(取决于不可重分发的调试运行时)。Dependency Walker可以很好地解决这一问题。
约翰尼·布洛尼

使用jnetpcap-library有相同的问题。依赖性winpcap不再安装在计算机上,并且异常消息具有误导性
BlackFlag

我认为这可能是我的情况。
I.Tyger,

如今,依赖步行者正变得“长牙”。它根本无法打开最近的Windows 10/64位dll,因此我仍然不知道缺少哪个库...呜呜。
Mark Storer


5

请验证您的库路径是否正确。当然,您可以使用以下代码来检查您的库路径路径: System.out.println(System.getProperty("java.library.path"));

您可以在启动Java应用程序时指定java.library.path

java -Djava.library.path=path ...

4

如果使用64位JRE加载dll的32位版本,则可能会出现此问题。这是我的情况。


这很可能也是我的情况。如果有人知道我知道的解决方法;除了加载64位版本,因为在这种情况下,该过程不是dll,而是chromedriver.exeChrome的Selenium驱动程序,据我所知,它仅是32位版本。
SantiBailors,2016年

4

确实有相同的问题,安装时,XP的机器上javacv,并opencv在与Eclipse结合。原来我缺少以下文件:

  • msvcp100.dll
  • msvcr100.dll

安装这些文件后,项目将编译并运行正常。


安装“ Microsoft Visual C ++ 2010 SP1可再发行组件包(x86)”后,我遇到的类似问题也消失了
Kirill Mikhailov

2
  • 简短答案:对于“找不到依赖库”错误,请检查您的$ PATH(对应于下面的项目符号#3)
  • 长答案:
    1. 纯Java世界:jvm使用“ Classpath”查找类文件
    2. JNI世界(Java /本地边界):jvm使用“ java.library.path”(默认为$ PATH)来查找dll
    3. 纯原生世界:原生代码使用$ PATH加载其他dll

2

我在keepsafe上发现了一篇很棒的文章,这篇文章也经历了同样的事情。它对我有用,所以希望它对您也有帮助!如果您有兴趣,请阅读(在Android上加载本机库的危险)或仅使用

compile 'com.getkeepsafe.relinker:relinker:1.2.3'

并更换

System.loadLibrary("myLibrary");

ReLinker.loadLibrary(context, "mylibrary");

1

我曾经遇到过完全相同的问题,终于解决了。

我将所有相关的DLL放入存储mylib.dll的同一文件夹中,并确保JAVA编译器可以找到它(如果编译路径中没有mylib.dll,则在编译过程中会报告此错误)。需要注意的重要一点是,必须确保所有从属库与mylib.dll具有相同的版本,例如,如果mylib.dll是发行版,则还应将所有其从属库的发行版放在此处。 。

希望这可以帮助遇到相同问题的其他人。


1

我遇到了同样的问题,我尝试了此处发布的所有内容进行修复,但没有一个适合我。就我而言,我正在使用Cygwin来编译dll。看来JVM试图在虚拟Cygwin路径中找到JRE DLL。我将Cygwin的虚拟目录路径添加到JRE的DLL中,并且现在可以使用。我做了类似的事情:

SET PATH =“ / cygdrive / c / Program Files / Java / jdk1.8.0_45”;%PATH%


1

在我的情况下,我试图通过Eclipse中的连接器在Tomcat 7中运行Java Web服务。当我将war文件部署到笔记本电脑上的Tomcat 7实例时,该应用程序运行良好。该应用程序需要用于“ IBM DB2 9.5”的jdbc type 2驱动程序。出于某种奇怪的原因,Eclispe中的连接器无法查看或使用IBM DB2环境变量中的路径来访问作为jcc客户端安装在我的笔记本电脑上的dll文件。该错误消息表明它找不到db2jcct2 dll文件,或者找不到该dll文件的从属库。最终,我删除了连接器并对其进行了重建。然后它正常工作。我在此处将此解决方案作为文档添加,因为在其他任何地方都找不到该特定解决方案。


0

创建静态库对我有用,使用进行编译g++ -static。它将依赖库与构建包捆绑在一起。



0

将所需的dll放在文件夹中,并在PATH环境变量中设置文件夹路径。确保反映了更新的环境PATH变量。


0

将两个Android项目合并为一个项目后,我遇到了ffmpeg库的相同问题。

实际问题是由于ffmpeg库的两个不同版本而来的,但它们在内存中加载了相同的名称。一个库放在JNiLibs中,而另一个库放在另一个用作模块的库中。我无法修改模块的代码,因为它是只读的,所以我将自己的代码中使用的代码重命名为ffmpegCamera,并将其以相同的名称加载到内存中。

System.loadLibrary("ffmpegCamera");

这解决了该问题,现在两个版本的库都可以很好地加载,并且在内存中分别加载了名称和进程ID。


0

调用时System.loadLibrary(),JVM将在java.library.path本地库中查找。但是,如果该本机库声明了对其他本机库的任何依赖关系,则操作系统将承担查找那些本机库依赖项的任务。

由于操作系统没有的概念java.library.path,因此不会看到您放置在java.library.path上的任何目录。相反,它将仅在操作系统的PATH环境变量上搜索目录。如果本机库依赖项是操作系统本机库,则完全可以,因为它将在PATH上找到。但是,如果本机库依赖项是您或其他人创建的本机库,则除非将其放在PATH中,否则将不会在PATH中找到它。此行为是奇怪的,出乎意料的,并且没有得到充分的记录,但已在OpenJDK问题跟踪器中进行了记录。您还可以在此处找到另一个StackOverflow答案,以加强此解释。

因此,您有两种选择。您可以使用,以正确的依赖关系顺序加载每个本机库System.loadLibrary(),也可以修改PATH以包括存储本机库的目录。


-2
  1. 转到http://tess4j.sourceforge.net/usage.html并单击Visual C++ Redistributable for VS2012
  2. 下载并运行VSU_4\vcredist_x64.exeVSU_4\vcredist_x84.exe取决于您的系统配置
  3. dll文件lib以及其他库(例如\lib\win32-x86\your dll files)放入文件夹中。
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.