Reputation: 8960
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
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
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:
loadLibrary()
on a .so
file that implements the function Java_com_mycompany_myproduct_Foo_do_1foo()
. Let's call this libctinative.so
.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 wayUpvotes: 3