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

JNI Unsatisfied Link Error in Eclipse Can't find dependent Libraries

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

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)

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

<string> 是头文件,如果包含 #include <string> 指令的 C++ 代码编译成功,这意味着标准包含文件夹的路径配置正确。

但是,根据您的项目配置为 linked 到 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 包)或与可执行文件放在同一文件夹中本身。

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

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

非常感谢heap underrun for your answer. I finally figured out a way to make it work. I used the Dependencies tool by lucasg,发现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 的顺序很重要。它不会在任何其他订单中工作。