Sergey Mikhanov
Sergey Mikhanov

Reputation: 8960

JNI invocation fails with UnsatisfiedLinkError

I'm getting UnsatisfiedLinkError when invoking C functions from JNI though my setup seems correct. Here's what I've done:

There's a Java class:

package com.mycompany.myproduct;

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

    public void native do_foo();
}

I've placed libexternal.so to the LD_LIBRARY_PATH, compiled the class, and executed javah over it. Resulting com_mycompany_myproduct_Foo.h file:

/* 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);

Implemented a C delegation in ctinative.c (not sure if extern "C" is needed there):

#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

Compiled that and got 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

Here's the output of nm ctinative.o (is having U there normal?):

0000000000000000 T Java_com_mycompany_myproduct_Foo_do_1foo
                 U do_foo

Placed that ctinative.o to LD_LIBRARY_PATH. Now when invoking Foo.do_foo() I'm getting UnsatisfiedLinkError:

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

If I remove ctinative.o from LD_LIBRARY_PATH the error does not change. If I remove libexternal.so from LD_LIBRARY_PATH then of course I'm getting:

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>

Any idea on what I'm doing wrong?

Upvotes: 2

Views: 2178

Answers (2)

user207421
user207421

Reputation: 311039

You have Java_com_mycompany_myproduct_Foo_do_1foo() but native void do_foo(). Was do_1foo() its name when you generated the .h/.c files? If you've changed it you have to regenerate.

Upvotes: 0

clstrfsck
clstrfsck

Reputation: 14847

OK, my experience with native libraries on Linux is limited to toy tests, however I have used them pretty extensively on Windows. I expect the mechanism is similar, but proceed with caution :)

Java ends up calling the Java_com_mycompany_myproduct_Foo_do_1foo() native function when you execute the method fooInstance.do_foo(). This is the native function that needs to be defined in libexternal.so (or whatever you choose to load with loadLibrary()).

If I understand your question correctly, you have compiled the function Java_com_mycompany_myproduct_Foo_do_1foo() into ctinative.o, and the implementation does not appear in libexternal.so. You can check this with objdump --dynamic-reloc libexternal.so.

I believe you need to have your native implementation of Java_com_mycompany_myproduct_Foo_do_1foo() compiled into libexternal.so, or alternatively you could link ctinative.o to produce a dynamic link library something like libctinative.so.

EDIT: To join the dots, the complete mechanism would be:

  1. Your java code calls loadLibrary() on a .so file that implements the function Java_com_mycompany_myproduct_Foo_do_1foo(). Let's call this libctinative.so.
  2. libctinative.so dynamically loads libexternal.so through the O/S's dynamic linking mechanism --- you don't need to do anything special to make this happen apart from compiling and linking libctinative.so in the right way
  3. Your program runs correctly, assuming no other issues :)

Upvotes: 3

Related Questions