JNI和C++ - UnsatisfiedLinkError

3

我成功使用JNI调用了一些C代码,但是当我想要改成C++时,无论我尝试调用哪个方法,JNI都会抛出一个"UnsatisfiedLinkError"错误。

这个是正常的:

g++ -c -Icryptopp562 -O3 -fPIC -fpermissive CI3CppEncryptionToolsImpl.cpp
gcc -I${JAVA_HOME}/include -O3 -shared -fPIC -o libCI3CppEncryptionTools.so de_zdv_research_emdu_CI3CppEncryptionTools.c CI3CppEncryptionToolsImpl.o -lcryptopp

我使用这个时会遇到一个 UnsatisfiedLinkError 错误:

g++ -c -Icryptopp562 -O3 -fPIC -fpermissive CI3CppEncryptionToolsImpl.cpp
g++ -I${JAVA_HOME}/include -O3 -shared -fPIC -fpermissive -o libCI3CppEncryptionTools.so de_zdv_research_emdu_CI3CppEncryptionTools.cpp CI3CppEncryptionToolsImpl.o -lcryptopp

生成的标题如下:
/* DO NOT EDIT THIS FILE - it is machine generated */
#include <jni.h>
/* Header for class de_zdv_research_emdu_CI3CppEncryptionTools */

#ifndef _Included_de_zdv_research_emdu_CI3CppEncryptionTools
#define _Included_de_zdv_research_emdu_CI3CppEncryptionTools
#ifdef __cplusplus
extern "C" {
#endif
/*
 * Class:     de_zdv_research_emdu_CI3CppEncryptionTools
 * Method:    encrypt
 * Signature: (Ljava/lang/String;)Ljava/lang/String;
 */
JNIEXPORT jstring JNICALL Java_de_zdv_research_emdu_CI3CppEncryptionTools_encrypt
  (JNIEnv *, jclass, jstring);

/*
 * Class:     de_zdv_research_emdu_CI3CppEncryptionTools
 * Method:    decrypt
 * Signature: (Ljava/lang/String;)Ljava/lang/String;
 */
JNIEXPORT jstring JNICALL Java_de_zdv_research_emdu_CI3CppEncryptionTools_decrypt
  (JNIEnv *, jclass, jstring);

#ifdef __cplusplus
}
#endif
#endif

以下是我的实现(.cpp),我省略了decrypt方法:

#include <jni.h>

#include "CI3CppEncryptionToolsImpl.h"

#include "de_zdv_research_emdu_CI3CppEncryptionTools.h"

jstring
Java_de_zdv_research_emdu_CI3CppEncryptionTools_encrypt(JNIEnv *env, jobject obj, jstring s) {

    return env->NewStringUTF(encrypt(env->GetStringUTFChars(s, JNI_FALSE)));

}

对于C版本,我只需要写return (*env)->NewStringUTF(env, encrypt((*env)->GetStringUTFChars(env, s, JNI_FALSE)));即可。

C版本可行,而C++版本则失败了:

Exception in thread "main" java.lang.UnsatisfiedLinkError: de.zdv.research.emdu.CI3CppEncryptionTools.encrypt(Ljava/lang/String;)Ljava/lang/String;

有什么想法吗?
3个回答

4
在实现文件(.cpp)中,您编写了以下函数:
jstring Java_de_zdv_research_emdu_CI3CppEncryptionTools_encrypt(JNIEnv *env, jobject obj, jstring s){
       //---------
}

请按照以下方式编写:

请将其编写为

JNIEXPORT jstring JNICALL Java_de_zdv_research_emdu_CI3CppEncryptionTools_encrypt
(JNIEnv *, jclass, jstring){
       //------------
}

我已经尝试过了,但很遗憾它没有起作用。据我所知,JNIEXPORTJNICALL是为确保正确的C绑定而设计的宏,但我看到一些例子中它们被省略了,但仍然能够正常工作。 - yvesonline
3
JNIEXPORT不是问题,问题在于你的实现参数与定义不同。为了匹配静态函数的JNI定义,你的第二个参数应该是jclass而不是jobject。 - Samhain
@manuell,请检查传递给函数的参数类型。 - rachana
@rachana 我认为 extern "C" 导出的函数名不会带有参数类型的修饰。那么错误的类型如何导致链接错误呢? - manuell
@rachana 第二条评论说类型应该是jclass,而不是jobject。你似乎没有理解我的问题。抱歉。 - manuell
显示剩余2条评论

1

谢谢!你是第一个说这话的人。非常有帮助的信息。 - Diego Velasco

0

确保Java能够在启动JVM的同一目录中找到您的动态本地库。还要检查您的动态库是否针对与您运行程序的JVM相同的架构进行编译(例如,32位JMV需要32位编译,64位JVM需要64位编译)。


我通过 java -Djava.library.path=lib ... 调用我的Java应用程序,以确保库文件被找到。正如我之前提到的那样,架构是匹配的,C版本可以毫无问题地运行。 - yvesonline

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接