Eclipse中的JNI Unsatisfied Link错误找不到依赖库

Posted

技术标签:

【中文标题】Eclipse中的JNI Unsatisfied Link错误找不到依赖库【英文标题】:JNI Unsatisfied Link Error in Eclipse Can't find dependent Libraries 【发布时间】:2021-11-17 06:33:27 【问题描述】:

我正在尝试从使用 C++ 样式字符串的 java 调用 C++ 函数。当我使用 C 风格的字符串时,该程序执行得很好,但就像我声明 std::string 以某种方式它无法再找到依赖库一样。我在 eclipse 环境中检查了我的包含文件夹,它确实包含 库及其所有依赖项。

package test_strings;

public class TestString 
    
    static 
        System.load("C:\\Users\\aurok\\eclipse-workspace\\native_cpp\\Debug\\libnative_cpp.dll");
    
    
    public native String sayHelloC();
    public native String sayHelloCpp();

    public static void main(String[] args) 
        
        TestString test = new TestString();
        
        System.out.println(test.sayHelloC());
        System.out.println(test.sayHelloCpp());

    


这是我的原生文件:

#include "test_strings_TestString.h"
#include<string>
using namespace std;

JNIEXPORT jstring JNICALL Java_test_1strings_TestString_sayHelloC
  (JNIEnv *env, jobject thisObj)

    jstring str = env->NewStringUTF("Hello World C-style !!");
    return str;


JNIEXPORT jstring JNICALL Java_test_1strings_TestString_sayHelloCpp
  (JNIEnv *env, jobject thisObj)
    //std::string str = "Hello World C++ style !!";
    //return env->NewStringUTF(str.c_str());
    return env->NewStringUTF("Hello World C++ style !!");


这段代码编译得很好,并且在 java 中运行良好,但是一旦我尝试使用 std::string 版本(注释),代码就会编译并创建动态库,但是在运行 java 代码时我得到以下错误:

Exception in thread "main" java.lang.UnsatisfiedLinkError: C:\Users\aurok\eclipse-workspace\native_cpp\Debug\libnative_cpp.dll: Can't find dependent libraries
    at java.base/jdk.internal.loader.NativeLibraries.load(Native Method)
    at java.base/jdk.internal.loader.NativeLibraries$NativeLibraryImpl.open(NativeLibraries.java:383)
    at java.base/jdk.internal.loader.NativeLibraries.loadLibrary(NativeLibraries.java:227)
    at java.base/jdk.internal.loader.NativeLibraries.loadLibrary(NativeLibraries.java:169)
    at java.base/java.lang.ClassLoader.loadLibrary(ClassLoader.java:2383)
    at java.base/java.lang.Runtime.load0(Runtime.java:746)
    at java.base/java.lang.System.load(System.java:1857)
    at test_strings.TestString.<clinit>(TestString.java:6)

我搜索了各种来源以寻找可能的解释,但找不到。伙计们,帮帮我!

【问题讨论】:

【参考方案1】:

&lt;string&gt; 是一个头文件,如果你的 C++ 代码包含#include &lt;string&gt; 指令编译这意味着标准包含文件夹的路径配置正确。

但是,根据您的项目如何配置为链接到 C 和 C++ 运行时库(静态或动态),生成的可执行文件可能依赖也可能不依赖额外的 DLL。 (例如,对于 Microsoft Visual Studio 2019 C++ 编译器,C 运行时库 DLL 为 vcruntime140.dll,C++ 运行时库 DLL 为 msvcp140.dll。)

使用std::string 可能会导致您的可执行文件依赖于 C++ 运行时库 DLL(除了 C 运行时 DLL),并且可能在与可执行文件相同的文件夹中找不到它(并且不在 DLL 搜索路径中) )。

在 Windows 上,C 运行时 DLL 通常已在系统范围内可用,但 C++ 运行时 DLL 需要安装(使用 Microsoft Visual C++ Redistributable 包)或与可执行文件本身放在同一文件夹中。

另一种选择是静态链接运行时库,因此生成的可执行文件不会有那些 DLL 依赖项。但通常,动态链接是首选。

请注意,根据您在 Eclipse IDE 中使用的 C++ 编译器 - GCC (G++)、Clang、MSVC 或其他 - 所需的 C++ 运行时 DLL 将具有不同的文件名。

【讨论】:

【参考方案2】:

非常感谢heap underrun 的回答。我终于想出了一个让它工作的方法。我使用lucasg 的Dependencies tool 发现 libgcc_s_seh-1.dlllibstdc++-6.dll 丢失了,即使它们存在于 MinGW bin 中。

所以我明确地将它们添加到与我的动态库相同的文件夹中,并将它们加载到 java 虚拟环境中。这就是 java 端现在的样子:

package test_strings;

import java.io.IOException;

public class TestString 
    
    static 
        System.load("C:\\Users\\aurok\\eclipse-workspace\\native_cpp\\Debug\\libwinpthread-1.dll");
        System.load("C:\\Users\\aurok\\eclipse-workspace\\native_cpp\\Debug\\libgcc_s_seh-1.dll");
        System.load("C:\\Users\\aurok\\eclipse-workspace\\native_cpp\\Debug\\libstdc++-6.dll.dll");
        System.load("C:\\Users\\aurok\\eclipse-workspace\\native_cpp\\Debug\\libnative_cpp.dll");
    
    
    public native String sayHelloC();
    public native String sayHelloCpp();

    public static void main(String[] args) 
        
        TestString test = new TestString();
        
        System.out.println(test.sayHelloC());
        System.out.println(test.sayHelloCpp());

    


注意:加载 dll 的顺序很重要。它不会以任何其他顺序工作。

【讨论】:

很高兴知道您已经解决了这个问题。但是您需要使用System.load() 显式加载 C++ 运行时库及其依赖库似乎是错误的。通常,如果这些运行时 DLL 位于(Java 进程的)当前目录或 PATH 中,Windows 加载程序本身(在加载 libnative_cpp.dll 时)会自动加载这些运行时 DLL。所以,我认为this answer 可能会帮助您摆脱不必要的依赖 DLL 的手动预加载。

以上是关于Eclipse中的JNI Unsatisfied Link错误找不到依赖库的主要内容,如果未能解决你的问题,请参考以下文章

Eclipse - 无法加载 JNI 共享库

Eclipse:无法加载 JNI 共享库 [重复]

Eclipse 报告“加载 JNI 共享库失败”[重复]

eclipse JNI项目迁移android studio相关问题

Eclipse集成JNI与AndroidNDK操作

如何编译jni