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】:<string>
是一个头文件,如果你的 C++ 代码包含#include <string>
指令编译这意味着标准包含文件夹的路径配置正确。
但是,根据您的项目如何配置为链接到 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.dll 和 libstdc++-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错误找不到依赖库的主要内容,如果未能解决你的问题,请参考以下文章