gpt4 book ai didi

c++ - 通过 JNI 调用 System.loadLibrary() 不会加载本地方法

转载 作者:行者123 更新时间:2023-11-28 06:24:52 26 4
gpt4 key购买 nike

我们有一个创建嵌入式 JVM 的 native C++ 应用程序。此 JVM 中的类使用 SWIG 包装器回调 C++ 对象方法(尽管 SWIG 的使用并不重要;它可以很容易地从 javah 生成 native 函数 stub )。例如,我们有一个带有本地方法的 Java 类:

package net.foo;
public class CppWrapJNI {
public final static native long foo(
long l, Stuff jarg1_, String s
);
}

在C++ DLL中有相应的实现:

extern "C" {
__declspec(dllexport) jlong JNICALL
Java_net_foo_CppWrapJNI_1foo(
JNIEnv *jenv, jclass jcls,
jlong jarg1, jobject jarg1_, jstring jarg2
) {
return 1;
}
}

假设这个 DLL 名为“foo.dll”。

然后我们尝试让 JVM 通过 JNI 加载 DLL,使用如下代码:

jclass cls = env->FindClass("java/lang/System");
jmethodID mid = env->GetStaticMethodID(
cls, "loadLibrary", "(Ljava/lang/String;)V"
);
jstring jstr = env->NewStringUTF("foo.dll");
env->CallStaticVoidMethodV(cls, mid, jstr);

一切正常,对 loadLibrary() 的调用报告没有错误(此处未显示 JNI 异常处理,但我们这样做了)。然而,稍后调用 CppWrapJNI.foo() 失败并出现如下错误:

java.lang.UnsatisfiedLinkError: 
net.foo.CppWrapJNI.foo(JLnet/foo/Stuff;Ljava/lang/String;)J

奇怪的是,如果我纯粹用 Java 编写测试工具,以相同的方式调用 loadLibrary,一切正常。这非常令人沮丧,因为我可以在线阅读的所有内容都表明这应该可以正常工作。

最佳答案

最后,我查看了 System.loadLibrary 的源代码:

@CallerSensitive
public static void loadLibrary(String libname) {
Runtime.getRuntime().loadLibrary0(Reflection.getCallerClass(), libname);
}

啊哈! Reflection.getCallerClass() 是关键。没有调用者类!它直接来自 C++。解决方案相当简单,围绕 System.load*() 编写一个外观,我们可以从 C++ 调用它,它将转过来调用系统方法:

public class SystemFacade {
public static void load(String path) {
java.lang.System.load(path);
}
public static void loadLibrary(String name) {
java.lang.System.loadLibrary(name);
}
}

瞧,它起作用了。据推测,Java 通过 JNI 代替 C++ 进行调用的任何变体也可以避免该问题。 @CallerSensitive 标签似乎是一个线索;不要通过 JNI 调用它们!我希望这篇文章能帮助其他人摆脱我所经历的挫败感。一直很疑惑,为什么加载成功了,但是没有找到任何符号。

关于c++ - 通过 JNI 调用 System.loadLibrary() 不会加载本地方法,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/28704830/

26 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com