92

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

当我运行我的程序时,它崩溃了

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

我搜索了这个网站(和其他网站),并尝试了一些修复:

  1. 我跑了依赖步行者。DW 给出了几个警告——libsndfile 所需的两个库 MPR.DLL 和 SHLWAPI.DLL 有“未解析的导入”——但DW 常见问题解答说可以安全地忽略这些警告。

  2. 我按照这里的建议修复了 mylib.dll 中的方法名称。方法名称不知何故被编译器弄乱了,但是我添加了链接器标志,并且 dll 方法名称现在与我的 jni 头文件中的名称完全匹配。

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

没有骰子。

有谁知道发生了什么?

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

4

18 回答 18

58

我很确定类路径和共享库搜索路径彼此无关。根据The JNI Book(这本书很旧),在 Windows 上,如果您不使用java.library.path系统属性,则 DLL 需要位于当前工作目录或 WindowsPATH环境变量中列出的目录中。


更新:

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

此外,您还可以阅读 Oracle 的 HTML 版本的JNI 规范。它位于 Java 网站的 Java 8 部分,因此希望会存在一段时间。


更新 2:

至少在 Java 8 中(我没有检查过早期版本)你可以这样做:

java -XshowSettings:properties -version

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

于 2011-05-23T03:36:16.133 回答
22

我想告知这个有趣的案例,在尝试了上述所有方法后,错误仍然存​​在。奇怪的是它可以在 Windows 7 计算机上运行,​​但在 Windows XP 上却不行。然后我使用dependency walker,发现在Windows XP上没有VC++ Runtime作为我的dll要求。在这里安装 VC++ Runtime 包后,它就像一个魅力。困扰我的是它一直告诉找不到依赖库,虽然直观地 JNI 依赖 dll 在那里,但最终证明 JNI 依赖 dll 需要另一个依赖 dl。我希望这有帮助。

于 2012-05-11T10:20:30.303 回答
16

您需要加载您的 JNI 库。

System.loadLibrary从 JVM 路径(JDK bin 路径)加载 DLL。

如果要加载带有路径的显式文件,请使用System.load ()

另请参阅:Java 中 System.load() 和 System.loadLibrary 之间的区别

于 2014-08-07T15:13:27.547 回答
9

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

于 2014-09-09T07:28:27.363 回答
6

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

  • msvcp100.dll
  • msvcr100.dll

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

于 2012-10-05T22:16:58.427 回答
6

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

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

java -Djava.library.path=path ...
于 2013-04-29T08:05:23.740 回答
2
  • 简短回答:对于“找不到依赖库”错误,请检查您的 $PATH (对应于下面的要点 #3)
  • 长答案:
    1. 纯java世界:jvm使用“Classpath”查找类文件
    2. JNI 世界(java/native 边界):jvm 使用“java.library.path”(默认为 $PATH)来查找 dll
    3. 纯原生世界:原生代码使用 $PATH 加载其他 dll
于 2017-10-30T11:59:00.713 回答
2

我在 keepsafe 上发现了一些朋友写的一篇很棒的文章,它和我做的一样。它对我有用,所以希望它也能帮助你!如果您有兴趣(The Perils of Loading Native Libraries on Android)或只是使用,请阅读

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

并更换

System.loadLibrary("myLibrary");

ReLinker.loadLibrary(context, "mylibrary");
于 2018-05-14T15:17:48.860 回答
2

安装 Microsoft Visual C++ 2010 SP1 Redistributable 已修复

于 2019-08-08T04:47:10.140 回答
1

我以前也有同样的问题,终于解决了。

我将所有依赖的 DLL 放到了存储 mylib.dll 的同一个文件夹中,并确保 JAVA 编译器可以找到它(如果编译路径中没有 mylib.dll,则在编译过程中会报错)。您需要注意的重要一点是,您必须确保所有依赖库与 mylib.dll 的版本相同,例如,如果您的 mylib.dll 是发布版本,那么您还应该将其所有依赖库的发布版本放在那里.

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

于 2011-10-09T09:09:28.097 回答
1

我遇到了同样的问题,我尝试了这里发布的所有内容来修复它,但没有一个对我有用。就我而言,我使用 Cygwin 来编译 dll。JVM 似乎试图在虚拟 Cygwin 路径中查找 JRE DLL。我将 Cygwin 的虚拟目录路径添加到 JRE 的 DLL 中,它现在可以工作了。我做了类似的事情:

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

于 2015-10-03T05:08:21.030 回答
1

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

于 2016-06-29T16:31:36.587 回答
1

调用System.loadLibrary()时,JVM 将查找java.library.path您的本机库。但是,如果该本机库声明了对其他本机库的任何依赖项,则操作系统将负责查找这些本机库依赖项。

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

所以,你有几个选择。您可以使用 以正确的依赖顺序加载每个本机库System.loadLibrary(),也可以修改 PATH 以包含存储本机库的目录。

于 2020-09-17T20:26:04.990 回答
0

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

于 2019-06-28T14:20:41.560 回答
0

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

于 2020-02-19T05:33:46.470 回答
0

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

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

System.loadLibrary("ffmpegCamera");

这解决了这个问题,现在两个版本的库都在内存中加载了单独的名称和进程 ID。

于 2020-03-09T12:08:46.487 回答
0

将 CI 迁移到新机器后,我遇到了同样的问题。即使在应用了上述所有解决方案之后,我仍然面临着它。

问题出在我的新机器上,其中安装了 Microsoft Visual C++ 2010 SP1 Redistributable x86。但是我的新机器有 64 位 CPU 和操作系统。所以解决方法是我刚刚从这里更新并安装了 64 位版本。

于 2021-10-05T10:23:24.400 回答
-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
于 2015-09-22T12:27:43.373 回答