JNI调用因UnsatisfiedLinkError而失败

时间:2010-12-06 11:35:06

标签: java java-native-interface

我在从JNI调用C函数时遇到UnsatisfiedLinkError,虽然我的设置似乎是正确的。这就是我所做的:

有一个Java类:

package com.mycompany.myproduct;

public class Foo {
    static {
        System.loadLibrary("external");
    }

    public void native do_foo();
}

我已将libexternal.so放置到LD_LIBRARY_PATH,编译了该类,并对其执行了javah。生成的com_mycompany_myproduct_Foo.h文件:

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

#ifndef _Included_com_mycompany_myproduct_Foo
#define _Included_com_mycompany_myproduct_Foo
#ifdef __cplusplus
extern "C" {
#endif
/*
 * Class:     com_com_mycompany_myproduct_Foo
 * Method:    do_foo
 * Signature: ()V
 */
JNIEXPORT void JNICALL Java_com_mycompany_myproduct_Foo_do_1foo(JNIEnv *, jobject);

ctinative.c中实施了C委托(不确定是否需要extern "C"):

#include "com_mycompany_myproduct_Foo.h"

#include "External.h"

#ifdef __cplusplus
extern "C" {
#endif

/*
 * Class:     com_com_mycompany_myproduct_Foo
 * Method:    do_foo
 * Signature: ()V
 */
JNIEXPORT void JNICALL Java_com_mycompany_myproduct_Foo_do_1foo(JNIEnv *, jobject) {
    do_foo();   // this is a function that defined in External.h
}

#ifdef __cplusplus
}
#endif

编译并得到ctinative.o

gcc -x c -g -m64 -DUNIX=1 -DUSE_SBUF=1 -DMAIN_VERSION=0 -DC_VER=7 -I$(EXTERNAL_SDK_ROOT)/include -I$(JAVA_HOME)/include -I$(JAVA_HOME)/include/linux -o ctinative.o -c ctinative.c

以下是nm ctinative.o的输出(U正常吗?):

0000000000000000 T Java_com_mycompany_myproduct_Foo_do_1foo
                 U do_foo

ctinative.o置于LD_LIBRARY_PATH。现在,在调用Foo.do_foo()时,我收到了UnsatisfiedLinkError:

java.lang.UnsatisfiedLinkError: com.mycompany.myproduct.Foo.do_foo()V
at com.mycompany.myproduct.Foo.do_foo(Native Method)

如果我从ctinative.o删除LD_LIBRARY_PATH,则错误不会更改。如果我从libexternal.so删除LD_LIBRARY_PATH,那么我当然会得到:

java.lang.UnsatisfiedLinkError: no external in java.library.path
at java.lang.ClassLoader.loadLibrary(ClassLoader.java:1734)
at java.lang.Runtime.loadLibrary0(Runtime.java:823)
at java.lang.System.loadLibrary(System.java:1028)
at com.mycompany.myproduct.Foo.<clinit>

对我做错了什么的想法?

2 个答案:

答案 0 :(得分:2)

好吧,我在Linux上使用本机库的经验仅限于玩具测试,但我在Windows上使用它们非常广泛。我希望机制类似,但要谨慎行事:)

当您执行方法Java_com_mycompany_myproduct_Foo_do_1foo()时,Java最终会调用fooInstance.do_foo()本机函数。这是需要在libexternal.so中定义的本机函数(或者您选择使用loadLibrary()加载的任何内容)。

如果我正确理解了您的问题,您已将函数Java_com_mycompany_myproduct_Foo_do_1foo()编译为ctinative.o,并且该实现未显示在libexternal.so中。您可以使用objdump --dynamic-reloc libexternal.so进行检查。

我认为您需要将Java_com_mycompany_myproduct_Foo_do_1foo()的原生实施汇编到libexternal.so,或者您可以链接ctinative.o以生成类似libctinative.so的动态链接库。

编辑:要加入点,完整的机制将是:

  1. 您的java代码在实现函数loadLibrary()的{​​{1}}文件上调用.so。我们称之为Java_com_mycompany_myproduct_Foo_do_1foo()
  2. libctinative.so通过O / S的动态链接机制动态加载libctinative.so - 除了编译和链接libexternal.so之外,您不需要做任何特殊的事情来实现这一点正确的方式
  3. 假设没有其他问题,您的程序运行正常:)

答案 1 :(得分:0)

您有Java_com_mycompany_myproduct_Foo_do_1foo()但是本机void do_foo()。生成.h / .c文件时,do_1foo()是否为其名称?如果你改变它,你必须重新生成。