java.lang.UnsatisfiedLinkError: Ubuntu 上的 TestJni.print(LA;)V 错误

Posted

技术标签:

【中文标题】java.lang.UnsatisfiedLinkError: Ubuntu 上的 TestJni.print(LA;)V 错误【英文标题】:java.lang.UnsatisfiedLinkError: TestJni.print(LA;)V error on Ubuntu 【发布时间】:2015-02-15 18:09:19 【问题描述】:

我知道这是一个经常出现的问题,在网上搜索后,问题仍然没有解决。 -Djava.library.path 已添加到命令中。

这是我的 java 文件

public class TestJni

        public native void print(A a);

        static
                System.loadLibrary("MyJni");
        

        public static void main(String []args)
                new TestJni().print(new A());
        

class A
        void show()
                System.out.println("In a show function");

        

我正在尝试创建一个实例“a”,它是 A 类。 将其传递给本地方法 print 并让本地方法调用 show() 方法。 将.java编译成.class

javac TestJni.java

现在我有了三个文件:A.class TestJni.class TestJni.java

使用

javah -classpath . TestJni

获取 .h 文件,如下所示:

/* DO NOT EDIT THIS FILE - it is machine generated */
#include <jni.h>
/* Header for class TestJni */

#ifndef _Included_TestJni
#define _Included_TestJni
#ifdef __cplusplus
extern "C" 
#endif
/*
 * Class:     TestJni
 * Method:    print
 * Signature: (LA;)V
 */
JNIEXPORT void JNICALL Java_TestJni_print
  (JNIEnv *, jobject, jobject);

#ifdef __cplusplus

#endif
#endif

将其重命名为 MyJni.h

mv TestJni.h MyJni.h

通过

创建 MyJni.c
vim MyJni.c

MyJni.c 的内容是:

/* DO NOT EDIT THIS FILE - it is machine generated */
#include <jni.h>
#include "MyJni.h"
/* Header for class TestJni */

#ifndef _Included_TestJni
#define _Included_TestJni
#ifdef __cplusplus
extern "C" 
#endif
/*
 * Class:     TestJni
 * Method:    print
 * Signature: (LA;)V
 */
JNIEXPORT void JNICALL Java_TestJni_print
  (JNIEnv *env, jobject obj, jobject o)
    jclass cls = (*env)->GetObjectClass(env, o);
    jmethodID mid = (*env)->GetMethodID(env, cls, "show", "()V");
    (*env)->CallVoidMethod(env, o, mid);



#ifdef __cplusplus

#endif
#endif

构建.so文件

gcc -fPIC -shared -o libMyJni.so MyJni.c -I. -I$JAVA_HOME/include -I$JAVA_HOME/include/linux

现在我的目录中有 5 个文件 [A.class libMyJni.so MyJni.c MyJni.h TestJni.class TestJni.java]:/home/grid/code/tmp

运行java程序:

java -cp . -Djava.library.path=. TestJni

现在我得到的错误是

Exception in thread "main" java.lang.UnsatisfiedLinkError: TestJni.print(LA;)V
    at TestJni.print(Native Method)
    at TestJni.main(TestJni.java:10)

我在 Ubuntu 14.10 下编码,gcc 程序是默认程序。 我真的无法弄清楚出了什么问题。 请帮我纠正程序。 提前非常感谢您!!!

【问题讨论】:

【参考方案1】:

删除

#ifndef _Included_TestJni
#define _Included_TestJni

...

#endif

来自源文件。您已经在标题中 #defined 包含保护,因此这有效地消除了代码。

【讨论】:

非常感谢!这正是我正在寻找的。但是如果代码在源文件和听者中出现两次,程序实际上做了什么? #include源文件中的标头,与写标头内容代替#include指令的效果相同。由于标头#defines 是_Included_TestJni 宏,所以它是在这个地方之后定义的。在源代码的后面,你说#ifndef _Included_TestJni,意思是:如果_Included_TestJni 没有定义就使用这个东西。因为定义了_Included_TestJni,所以没有使用东东,也没有编译函数。因此它不在库中,因此 JVM 无法在那里找到它。【参考方案2】:

删除#include "MyJni.h"

#ifndef _Included_TestJni
#define _Included_TestJni
//..
#endif

Exception in thread "main" java.lang.UnsatisfiedLinkError: TestJni.print(LA;)V 这通常发生在 JNI 在您的库中找不到符号定义时。您可以使用nm 来分析您调用的JNI 函数,看看它是否在您的库中定义和导出。

$ nm libMyJni.so 
00000000000005ac T Java_TestJni_print
0000000000200e40 a _DYNAMIC
0000000000200fe8 a _GLOBAL_OFFSET_TABLE_
                 w _Jv_RegisterClasses
0000000000200e20 d __CTOR_END__
0000000000200e18 d __CTOR_LIST__

【讨论】:

nm 的提示在检查.so 文件时非常有用。非常感谢!你能解释一下#include "MyJni.h"#ifndef _Included_TestJni #define _Included_TestJni //.. #endif之间的冲突吗?【参考方案3】:

您可以尝试使用System.load。 iirc System.loadLibrary 从默认位置加载 .so/.dll 文件。 System.load 应该使用 .so/.dll 文件的绝对路径。

【讨论】:

我尝试改用System.load("/home/grid/code/tmp/libMyJni.so");。但结果是一样的。我认为编码应该有问题。你这么认为吗? @krave 也许它与重命名有关?自从我完成 JNI 以来已经有一段时间了.. 错误不是来自load()loadLibrary()。当他调用本机方法时,它就来了。

以上是关于java.lang.UnsatisfiedLinkError: Ubuntu 上的 TestJni.print(LA;)V 错误的主要内容,如果未能解决你的问题,请参考以下文章