如何修复 JNI 项目中的 UnsatisfiedLinkError(找不到依赖库)
Posted
技术标签:
【中文标题】如何修复 JNI 项目中的 UnsatisfiedLinkError(找不到依赖库)【英文标题】:How to fix an UnsatisfiedLinkError (Can't find dependent libraries) in a JNI project 【发布时间】:2011-08-30 20:03:48 【问题描述】:我正在开发一个使用 JNI 的 Java 项目。 JNI 调用我自己编写的自定义库,比如说 mylib.dll,它依赖于第 3 方库 libsndfile-1.dll。
当我运行我的程序时它崩溃了
java.lang.UnsatisfiedLinkError: C:\...path...\mylib.dll: Can't find dependent libraries.
我已经搜索了这个网站(和其他网站)并尝试了一些修复方法:
我运行了依赖walker。 DW 给出了一些警告——libsndfile 所需的两个库 MPR.DLL 和 SHLWAPI.DLL 有“未解析的导入”——但 DW FAQ 表示可以安全地忽略这些警告。
按照here 的建议,我修复了 mylib.dll 中的方法名称。方法名称不知何故被编译器弄乱了,但我添加了链接器标志,现在 dll 方法名称与我的 jni 头文件中的名称完全匹配。
我将所有这些 DLL 放在同一个目录中 - 与调用它们的 .jar 相同的目录 - 以确保它们位于正确的 PATH 上。
没有骰子。
有人知道发生了什么吗?
我正在 MacBook Pro 上(通过 Parallels)在 Visual Studio 2010 中进行开发。我正在东芝笔记本电脑上的 Windows XP 中进行测试。
【问题讨论】:
你设置 -Djava.library.path 了吗? 实际上我没有,因为我没有从命令行启动程序。我正在为 Processing (processing.org) 编写一个库,而 Processing 负责启动我的代码。不过,我在运行时检查了 java 库路径,包含我的 DLL 的文件夹就在上面。 在 Windows 上,我们必须将 .dll 文件放在 [JRE]\bin 目录中(与 java.exe 等相同的位置),以便让 Java 自动查看它们而不必弄脏使用命令行选项或环境变量。 嗯...好的,我尝试将所有 .dll 文件放入 [JRE]\bin 中。这行得通! 查看.
在您的PATH
中相对于其他目录(JRE、Windows 等)的位置。较早的条目之一可能提供了与您尝试从当前目录加载的库不兼容的库版本。在我的 PATH 中移动 .
对我有用,并且让我不必用我的库污染 JRE 目录。
【参考方案1】:
我很确定类路径和共享库搜索路径之间没有什么关系。根据The JNI Book(诚然是旧的),在Windows 上,如果您不使用java.library.path
系统属性,DLL 需要位于当前工作目录或Windows PATH
环境变量中列出的目录中。
更新:
Oracle 似乎已从其网站上删除了该 PDF。我已经更新了上面的链接,指向德克萨斯大学阿灵顿分校的 PDF 实例。
此外,您还可以阅读 Oracle 的 html 版本的JNI Specification。它位于 Java 网站的 Java 8 部分,因此希望会存在一段时间。
更新 2:
至少在 Java 8 中(我没有检查过早期版本)你可以这样做:
java -XshowSettings:properties -version
查找共享库搜索路径。在该输出中查找 java.library.path
属性的值。
【讨论】:
是的,CLASSPATH
根本不用。我也不确定是否使用了cwd
。 java.library.path
或简单的 PATH
都可以。 @dB',你现在得到它们的地方是错误。
非常感谢大家!我认为这里的部分问题是我在 Windows PATH 环境变量 java.library.path 和 java CLASSPATH 之间的混淆。现在一切都变得更有意义了。
请您解释一下您是如何克服这个问题的?
@SL_User 我认为如果将库所在的目录添加到环境变量“path”并重新启动命令提示符或终端,它应该可以修复它。 Java 在 classpath 下查找 jars,在 path 下查找库。
基于这个答案,看起来更新 2 的命令至少从 Java 7 开始就可用:***.com/a/8472139/901641【参考方案2】:
我以前也有同样的问题,终于解决了。
我把所有依赖的 DLL 放到 mylib.dll 所在的同一个文件夹中,并确保 JAVA 编译器可以找到它(如果编译路径中没有 mylib.dll,编译时会报错)。您需要注意的重要一点是,您必须确保所有依赖库与 mylib.dll 的版本相同,例如,如果您的 mylib.dll 是发布版本,那么您还应该将其所有依赖库的发布版本放在那里.
希望这可以帮助遇到同样问题的其他人。
【讨论】:
【参考方案3】:我想告知这个有趣的案例,在尝试了上述所有方法后,错误仍然存在。奇怪的是它可以在 Windows 7 计算机上运行,但在 Windows XP 上却不行。然后我使用dependency walker,发现在Windows XP上没有VC++ Runtime作为我的dll要求。安装 VC++ Runtime 包here 后,它就像一个魅力。困扰我的是它一直告诉找不到依赖库,虽然直观地 JNI 依赖 dll 在那里,但最终证明 JNI 依赖 dll 需要另一个依赖 dl。我希望这会有所帮助。
【讨论】:
该消息是正确的,尽管在这种情况下具有误导性。我在测试盒上缺少 VC++ 运行时和在调试模式下编译的库(取决于 non-redistributable 调试运行时)。 Dependency Walker 对解决这个问题很有帮助。 在使用 jnetpcap-library 时遇到了同样的问题。机器上不再安装依赖项 winpcap 并且异常消息具有误导性 我认为这可能是我的情况。 这些天来,dependency walker 变得相当“长在牙齿上”。它根本无法打开最近的 Windows 10/64 位 dll,所以我仍然不知道缺少哪个库...... Whee。 Dependency Walker 有一个现代替代品:github.com/lucasg/Dependencies【参考方案4】:在与 Eclipse 结合安装 javacv
和 opencv
时,在 XP 机器上确实存在相同的问题。原来我缺少以下文件:
一旦安装了这些,项目编译并运行正常。
【讨论】:
我有类似的问题,安装“Microsoft Visual C++ 2010 SP1 Redistributable Package (x86)”后就消失了【参考方案5】:请验证您的库路径是否正确。当然,您可以使用以下代码来检查您的库路径路径:
System.out.println(System.getProperty("java.library.path"));
您可以在启动 Java 应用程序时指定 java.library.path:
java -Djava.library.path=path ...
【讨论】:
【参考方案6】:您需要加载您的 JNI 库。
System.loadLibrary 从 JVM 路径(JDK bin 路径)加载 DLL。
如果要加载带有路径的显式文件,请使用 System.load()
另见:Difference between System.load() and System.loadLibrary in Java
【讨论】:
【参考方案7】:如果您使用 64 位 JRE 加载 32 位版本的 dll,您可能会遇到此问题。这是我的情况。
【讨论】:
这很可能也是我的情况;如果有人知道已知的解决方法,我会感兴趣;除了加载 64 位版本,在这种情况下,进程不是 dll,而是chromedriver.exe
,Chrome 的 Selenium 驱动程序,据我所知,它只有 32 位版本。【参考方案8】:
-
转到http://tess4j.sourceforge.net/usage.html 并点击
Visual C++ Redistributable for VS2012
下载并运行 VSU_4\vcredist_x64.exe
或 VSU_4\vcredist_x84.exe
,具体取决于您的系统配置
将您的dll
文件与其他库(例如\lib\win32-x86\your dll files
)一起放入lib
文件夹。
【讨论】:
【参考方案9】:我遇到了同样的问题,我尝试了这里发布的所有内容来修复它,但没有一个对我有用。 就我而言,我使用 Cygwin 来编译 dll。 JVM 似乎试图在虚拟 Cygwin 路径中查找 JRE DLL。 我将 Cygwin 的虚拟目录路径添加到 JRE 的 DLL 中,它现在可以工作了。 我做了类似的事情:
SET PATH="/cygdrive/c/Program Files/Java/jdk1.8.0_45";%PATH%
【讨论】:
【参考方案10】:在我的情况下,我试图通过 Eclipse 中的连接器在 Tomcat 7 中运行 java Web 服务。当我将战争文件部署到笔记本电脑上的 Tomcat 7 实例时,该应用程序运行良好。该应用程序需要用于“IBM DB2 9.5”的 jdbc 类型 2 驱动程序。由于某些奇怪的原因,Eclispe 中的连接器无法查看或使用 IBM DB2 环境变量中的路径来访问作为 jcc 客户端安装在我的笔记本电脑上的 dll 文件。错误消息要么表明它未能找到 db2jcct2 dll 文件,要么它未能找到该 dll 文件的依赖库。最终,我删除了连接器并重建了它。然后它工作正常。我在此处将此解决方案添加为文档,因为我无法在其他任何地方找到此特定解决方案。
【讨论】:
【参考方案11】: 简短回答:对于“找不到依赖库”错误,请检查您的 $PATH(对应于下面的要点 #3) 长答案:-
纯java世界:jvm使用“Classpath”查找类文件
JNI 世界(java/native 边界):jvm 使用“java.library.path”(默认为 $PATH)来查找 dll
纯原生世界:原生代码使用 $PATH 加载其他 dll
【讨论】:
【参考方案12】:我在 keepsafe 上发现了一些朋友写的一篇很棒的文章,它和我做的一样。它对我有用,所以希望它也能帮助你!如果您有兴趣,请阅读 (The Perils of Loading Native Libraries on android) 或直接使用
compile 'com.getkeepsafe.relinker:relinker:1.2.3'
替换
System.loadLibrary("myLibrary");
与
ReLinker.loadLibrary(context, "mylibrary");
【讨论】:
【参考方案13】:创建静态库对我有用,使用 g++ -static
编译。它将依赖库与构建捆绑在一起。
【讨论】:
【参考方案14】:安装 Microsoft Visual C++ 2010 SP1 Redistributable 修复它
【讨论】:
另外,请确认您的系统是 x64 还是 x86,并从here 下载适当的版本【参考方案15】:将所需的 dll 放在文件夹中,并在 PATH 环境变量中设置文件夹路径。 确保反映更新的环境 PATH 变量。
【讨论】:
【参考方案16】:在将两个 Android 项目合并为一个项目后,我遇到了与 ffmpeg 库相同的问题。
实际上问题是由于 ffmpeg 库的两个不同版本而出现的,但它们在内存中加载了相同的名称。一个库被放置在 JNiLibs 中,而另一个库位于另一个用作模块的库中。我无法修改模块的代码,因为它是只读的,所以我将我自己代码中使用的代码重命名为 ffmpegCamera 并以相同的名称将其加载到内存中。
System.loadLibrary("ffmpegCamera");
这解决了问题,现在两个版本的库都可以很好地加载,并且内存中的名称和进程 ID 是分开的。
【讨论】:
【参考方案17】:当调用System.loadLibrary()
时,JVM 将在java.library.path
上查找您的本机库。但是,如果该本地库声明了对其他本地库的任何依赖项,则操作系统将负责查找这些本地库依赖项。
由于操作系统没有java.library.path
的概念,它不会看到您放置在java.library.path 上的任何目录。相反,它只会搜索操作系统的 PATH 环境变量中的目录。如果本机库依赖项是操作系统本机库,这完全没问题,因为它将在 PATH 中找到。但是,如果本机库依赖项是您或其他人创建的本机库,则除非您将其放置在 PATH 中,否则将无法在 PATH 上找到它。这种行为很奇怪,出乎意料,并且没有很好的记录,但它记录在 OpenJDK 问题跟踪器here 中。您还可以找到另一个 *** 答案来强化此解释,here。
所以,您有几个选择。您可以使用 System.loadLibrary()
以正确的依赖顺序加载每个本机库,也可以修改 PATH 以包含存储本机库的目录。
【讨论】:
这帮助我理解了如何从操作系统的角度搜索 lib。我的问题是当我加载(通过 System loadLibrary)tibrvj 时,我得到了找不到依赖库的错误。将 %TIBRV_HOME%/lib 附加到 PATH(甚至通过运行配置)解决了这个问题。谢谢【参考方案18】:将 CI 迁移到新机器后,我遇到了同样的问题。 即使应用了上述所有解决方案,我仍然面临它。
问题出在我的新机器上,其中安装了 Microsoft Visual C++ 2010 SP1 Redistributable x86。但是我的新机器有 64 位 CPU 和操作系统。所以解决方法是我刚刚从here 更新并安装了 64 位版本。
【讨论】:
以上是关于如何修复 JNI 项目中的 UnsatisfiedLinkError(找不到依赖库)的主要内容,如果未能解决你的问题,请参考以下文章
如何修复 JNI 项目中的 UnsatisfiedLinkError(找不到依赖库)
带有 JNI 的 C++ 应用程序抛出错误“找不到 jvm.dll。重新安装应用程序可以修复....”
如何修复 env->NewObject() 上的 JNI 崩溃?
Error creating bean with name ‘tagServiceImpl‘: Unsatisfied dependency expressed through field
如何在使用 JNI 的 C++/Java 项目中使用 CRT 中的工具检测内存泄漏?
Spring - Error creating bean with name ‘XX‘: Unsatisfied dependency expressed through field ‘XX‘