如何修复 JNI 项目中的 UnsatisfiedLinkError(找不到依赖库)
我正在开发一个使用 JNI 的 Java 项目。 JNI 调用我自己编写的自定义库,例如 mylib.dll,它依赖于第 3 方库 libsndfile-1.dll。
当我运行我的程序时,它崩溃了,
java.lang.UnsatisfiedLinkError: C:\...path...\mylib.dll: Can't find dependent libraries.
我搜索了这个网站(和其他网站),并且我尝试了一些修复:
我运行了 dependency walker。 DW 给出了一些警告——libsndfile 所需的两个库 MPR.DLL 和 SHLWAPI.DLL 有“未解析的导入”——但是 DW FAQ 表示可以安全地忽略这些警告。
我按照建议修复了 mylib.dll 中的方法名称这里。方法名称不知何故被编译器破坏了,但我添加了链接器标志,并且 dll 方法名称现在与我的 jni 头文件中的名称完全匹配。
我将所有这些 DLL 放在同一个目录中(与调用它们的 .jar 相同的目录),以确保它们位于正确的 PATH 上。
没有骰子。
有人知道发生了什么事吗?
我正在 MacBook pro 上的 Visual Studio 2010 中进行开发(通过 Parallels)。我正在东芝笔记本电脑上的 Windows XP 中进行测试。
I'm working on a Java project that uses the JNI. The JNI calls a custom library that I've written myself, let's say mylib.dll, and that depends on a 3rd party library, libsndfile-1.dll.
When I run my program it crashes with
java.lang.UnsatisfiedLinkError: C:\...path...\mylib.dll: Can't find dependent libraries.
I've searched this site (and others) and I've tried a number of fixes:
I ran dependency walker. DW gave a couple of warnings -- that two libraries required by libsndfile, MPR.DLL and SHLWAPI.DLL, had "unresolved imports" -- but the DW FAQ said that these warnings could be safely ignored.
I fixed the method names in mylib.dll, as suggested here. The method names had somehow gotten mangled by the compiler, but I added linker flags and the dll method names now match those in my jni header file exactly.
I put all of these DLLs in the same directory -- the same directory as the .jar that calls them -- to ensure that they're on the right PATH.
No dice.
Does anyone have any idea what's going on?
I'm doing my development in Visual Studio 2010 on a MacBook pro (via Parallels). I'm doing my testing in Windows XP on a toshiba laptop.
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(19)
我很确定类路径和共享库搜索路径彼此没有什么关系。根据The JNI Book(诚然,是旧版本),在 Windows 上,如果不使用 java.library.path 系统属性,则 DLL 需要位于当前工作目录或 Windows PATH 中列出的目录中/代码> 环境变量。
更新:
Oracle 似乎已从其网站上删除了该 PDF。我更新了上面的链接,指向德克萨斯大学阿灵顿分校的 PDF 实例。
此外,您还可以阅读 Oracle 的 HTML 版本的 JNI 规范。它位于 Java 网站的 Java 8 部分,因此希望会存在一段时间。
更新2:
至少在Java 8中(我没有检查过早期版本)你可以这样做:
找到共享库搜索路径。在该输出中查找 java.library.path 属性的值。
I'm pretty sure the classpath and the shared library search path have little to do with each other. According to The JNI Book (which admittedly is old), on Windows if you do not use the
java.library.path
system property, the DLL needs to be in the current working directory or in a directory listed in the WindowsPATH
environment variable.Update:
Looks like Oracle has removed the PDF from its website. I've updated the link above to point to an instance of the PDF living at University of Texas - Arlington.
Also, you can also read Oracle's HTML version of the JNI Specification. That lives in the Java 8 section of the Java website and so hopefully will be around for a while.
Update 2:
At least in Java 8 (I haven't checked earlier versions) you can do:
to find the shared library search path. Look for the value of the
java.library.path
property in that output.我想告知这个有趣的案例,在尝试了上述所有方法后,错误仍然存在。奇怪的是它可以在 Windows 7 计算机上运行,但在 Windows XP 上却不能。然后我使用 dependency walker 并发现在 Windows XP 上没有 VC++ Runtime 作为我的 dll 要求。在此处安装 VC++ 运行时包后,它就像一个魅力。令我困扰的是它一直告诉我找不到依赖库,而直观上JNI依赖的dll就在那里,但最终发现JNI依赖的dll需要另一个依赖的dl。我希望这有帮助。
I want to inform this interesting case, after tried all the above method, the error is still there. The weird thing is it works on a Windows 7 computer, but on Windows XP it is not. Then I use dependency walker and found on the Windows XP there is no VC++ Runtime as my dll requirement. After installing VC++ Runtime package here it works like a charm. The thing that disturbed me is it keeps telling Can't find dependent libraries, while intuitively the JNI dependent dll is there, however it finally turns out the JNI dependent dll requires another dependent dl. I hope this helps.
您需要加载 JNI 库。
System.loadLibrary 从 JVM 路径加载 DLL (JDK bin 路径)。
如果要加载带有路径的显式文件,请使用 System.load()
另请参阅:系统之间的差异Java 中的 .load() 和 System.loadLibrary
You need to load your JNI library.
System.loadLibrary loads the DLL from the JVM path (JDK bin path).
If you want to load an explicit file with a path, use System.load()
See also: Difference between System.load() and System.loadLibrary in Java
如果您使用 64 位 JRE 加载 32 位版本的 dll,则可能会遇到此问题。这就是我的情况。
If you load a 32 bit version of your dll with a 64 bit JRE you could have this issue. This was my case.
当调用 System.loadLibrary() 时,JVM 将在 java.library.path 中查找您的本机库。但是,如果该本机库声明了对其他本机库的任何依赖项,则操作系统将负责查找这些本机库依赖项。
由于操作系统没有 java.library.path 的概念,因此它不会看到您放置在 java.library.path 上的任何目录。相反,它只会搜索操作系统的 PATH 环境变量中的目录。如果本机库依赖项是操作系统本机库,则完全没问题,因为可以在 PATH 中找到它。但是,如果本机库依赖项是您或其他人创建的本机库,则除非您将其放置在那里,否则不会在 PATH 上找到它。这种行为很奇怪、出乎意料,并且没有详细记录,但它记录在 OpenJDK 问题跟踪器 中在这里。您还可以在此处找到另一个 StackOverflow 答案来强化这一解释。
所以,你有几个选择。您可以使用 System.loadLibrary() 以正确的依赖顺序加载每个本机库,也可以修改 PATH 以包含存储本机库的目录。
When calling
System.loadLibrary()
, the JVM will look on thejava.library.path
for your native library. However, if that native library declares any dependencies on other native libraries, then the operating system will be tasked with finding those native library dependencies.Since the operating system has no concept of the
java.library.path
, it will not see any directories you place on the java.library.path. Instead, it will only search the directories on PATH environment variable of the operating system. This is totally fine if the native library dependency is an operating system native library because it will be found on the PATH. However, if the native library dependency is a native library that you or someone else created, then it will not be found on the PATH unless you place it there. This behavior is strange, unexpected, and not well documented, but it is documented in the OpenJDK issue tracker here. You can also find another StackOverflow answer reinforcing this explanation, here.So, you have a couple of options. You could either load each native library in the correct dependency order using
System.loadLibrary()
, or you could modify the PATH to include the directories where your native libraries are stored.请检查您的库路径是否正确。当然,您可以使用以下代码来检查您的库路径路径:
System.out.println(System.getProperty("java.library.path"));
您可以在启动 Java 应用程序时指定 java.library.path:
Please verify your library path is right or not. Of course, you can use following code to check your library path path:
System.out.println(System.getProperty("java.library.path"));
You can appoint the java.library.path when launching a Java application:
与 Eclipse 结合安装
javacv
和opencv
时,在 XP 机器上遇到了相同的问题。结果发现我缺少以下文件:安装这些文件后,项目编译并运行正常。
Did have identical problem with on XP machine when installing
javacv
andopencv
in combination with Eclipse. It turned out that I was missing the following files:Once these were installed, the project compiled and ran OK.
我在 keepsafe 上发现了一些朋友写的一篇很棒的文章,其中也经历了与我相同的事情。它对我有用,所以希望它也能帮助你!如果您有兴趣,请阅读(在 Android 上加载本机库的危险)或仅使用
compile 'com.getkeepsafe.relinker:relinker:1.2.3'
并替换
为
I found a great article by some friends at keepsafe that went through the same thing I did. It worked for me, so hopefully it helps you out as well! Have a read if you're interested (The Perils of Loading Native Libraries on Android) or just use
compile 'com.getkeepsafe.relinker:relinker:1.2.3'
and replace
with
安装 Microsoft Visual C++ 2010 SP1 Redistributable 修复此问题
installing Microsoft Visual C++ 2010 SP1 Redistributable Fixed it
我以前也遇到过同样的问题,最后解决了。
我将所有依赖的 DLL 放入存储 mylib.dll 的同一文件夹中,并确保 JAVA 编译器可以找到它(如果编译路径中没有 mylib.dll,则编译时会报错)。您需要注意的重要一点是,您必须确保所有依赖库与 mylib.dll 具有相同的版本,例如,如果您的 mylib.dll 是发布版本,那么您还应该将其所有依赖库的发布版本放在那里。
希望这可以帮助遇到同样问题的其他人。
I used to have exactly the same problem, and finally it was solved.
I put all the dependent DLLs into the same folder where mylib.dll was stored and make sure the JAVA Compiler could find it (if there is no mylib.dll in the compilation path, there would be an error reporting this during compiling). The important thing you need to notice is you must make sure all the dependent libs are of the same version with mylib.dll, for example if your mylib.dll is release version then you should also put the release version of all its dependent libs there.
Hope this could help others who have encountered the same problem.
我遇到了同样的问题,我尝试了这里发布的所有内容来解决它,但没有一个对我有用。
就我而言,我使用 Cygwin 来编译 dll。 JVM 似乎尝试在虚拟 Cygwin 路径中查找 JRE DLL。
我将 Cygwin 的虚拟目录路径添加到 JRE 的 DLL,现在它可以工作了。
我做了类似的事情:
I had the same issue, and I tried everything what is posted here to fix it but none worked for me.
In my case I'm using Cygwin to compile the dll. It seems that JVM tries to find the JRE DLLs in the virtual Cygwin path.
I added the the Cygwin's virtual directory path to JRE's DLLs and it works now.
I did something like:
在我的情况下,我尝试通过 Eclipse 中的连接器在 Tomcat 7 中运行 java web 服务。当我将 war 文件部署到笔记本电脑上的 Tomcat 7 实例时,该应用程序运行良好。该应用程序需要“IBM DB2 9.5”的 jdbc 类型 2 驱动程序。由于某些奇怪的原因,Eclispe 中的连接器无法查看或使用 IBM DB2 环境变量中的路径来访问作为 jcc 客户端安装在我的笔记本电脑上的 dll 文件。该错误消息要么指出无法找到 db2jcct2 dll 文件,要么无法找到该 dll 文件的依赖库。最终,我删除了连接器并重建了它。然后就正常工作了。我在此处添加此解决方案作为文档,因为我未能在其他地方找到此特定解决方案。
In my situation, I was trying to run a java web service in Tomcat 7 via a connector in Eclipse. The app ran well when I deployed the war file to an instance of Tomcat 7 on my laptop. The app requires a jdbc type 2 driver for "IBM DB2 9.5". For some odd reason the connector in Eclispe could not see or use the paths in the IBM DB2 environment variables, to reach the dll files installed on my laptop as the jcc client. The error message either stated that it failed to find the db2jcct2 dll file or it failed to find the dependent libraries for that dll file. Ultimately, I deleted the connector and rebuilt it. Then it worked properly. I'm adding this solution here as documentation, because I failed to find this specific solution anywhere else.
创建静态库对我有用,使用
g++ -static
进行编译。它将依赖库与构建捆绑在一起。Creating static library worked for me, compiling using
g++ -static
. It bundles the dependent libraries along with the build.将所需的 dll 文件放入文件夹中,并在 PATH 环境变量中设置文件夹路径。
确保反映更新的环境 PATH 变量。
place the required dlls in folder and set the folder path in PATH environment variable.
make sure updated environment PATH variable is reflected.
将两个 Android 项目合并为一个项目后,我遇到了与 ffmpeg 库相同的问题。
实际上,问题是由于两个不同版本的 ffmpeg 库而出现的,但它们在内存中加载了相同的名称。一个库放置在 JNiLibs 中,而另一个库则放置在用作模块的另一个库中。我无法修改模块的代码,因为它是只读的,因此我将自己的代码中使用的代码重命名为 ffmpegCamera 并以相同的名称将其加载到内存中。
这解决了这个问题,现在两个版本的库都可以在内存中以单独的名称和进程 ID 的形式加载。
I was facing same issue with ffmpeg library after merging two Android projects as one project.
Actually issue was arriving due to two different versions of ffmpeg library but they were loaded with same names in memory. One library was placed in JNiLibs while other was inside another library used as module. I was not able to modify the code of module as it was readonly so I renamed the one used in my own code to ffmpegCamera and loaded it in memory with same name.
This resolved the issue and now both versions of libraries are loading well as separate name and process id in memory.
将 CI 迁移到新机器后,我遇到了同样的问题。
即使应用了上述所有解决方案后,我仍然面临着这个问题。
问题出在我的新机器上,其中安装了 Microsoft Visual C++ 2010 SP1 Redistributable x86。但我的新机器有 64 位 CPU 和操作系统。所以解决方法是我刚刚更新并安装了 这里。
I faced the same problem after migrating my CI into a new machine.
I was still facing it even after applying all the above solutions.
The problem was in my new machine, there was Microsoft Visual C++ 2010 SP1 Redistributable x86 installed in it. But my new machine was having 64-bit CPU and operating system. So the fix was that i just updated and installed the 64 bit version from here .
我遇到了同样的问题,找不到 nativewindow_awt.dll。解决办法是在环境变量中添加当前Java的jre/bin路径。
I had same problem and cannot find nativewindow_awt.dll. The solution was add the current Java's jre/bin path in the environment variables.
Visual C++ Redistributable for VS2012
VSU_4\vcredist_x64.exe
或VSU_4\vcredist_x84.exe
,具体取决于您的系统配置dll
文件以及其他库(例如lib
文件夹中的\lib\win32-x86\your dll 文件
)。Visual C++ Redistributable for VS2012
VSU_4\vcredist_x64.exe
orVSU_4\vcredist_x84.exe
depending upon your system configurationdll
files inside thelib
folder, along with your other libraries (eg\lib\win32-x86\your dll files
).