2
votes

java.lang.UnsatisfiedLinkError when using JNI.

My Testing Environment:

Ubuntu 12.04/64-bit
JDK 1.7
gcc (Ubuntu/Linaro 4.6.3-1ubuntu5)

This is my java source:

public class HelloJNI {
    static {
        //System.loadLibrary("libHelloJNI");
    }

    private native void sayHello() ;

    public static void main(String[] args){
        //System.getProperties().list(System.out);
        String lib_path = System.getProperty("java.library.path");
        System.out.println("java.library.path=" + lib_path);

        System.loadLibrary("libHelloJNI");

        HelloJNI myJNI = new HelloJNI();
        myJNI.sayHello();
    }
}

This is my C source:

#include <stdio.h>
#include "HelloJNI.h"

JNIEXPORT void JNICALL Java_HelloJNI_sayHello(JNIEnv *env, jobject thisObj)
{
    puts("Hello Momo. This is C code.");
    return;
}

This is my Makefile:

JNI_INC=-I"${JAVA_HOME}/include" -I"${JAVA_HOME}/include/linux"

JNI_LIB=libHelloJNI.so
JNI_OUT=$(JNI_LIB) HelloJNI.h HelloJNI.class
CFLAGS= $(JNI_INC) -fPIC -shared

all: $(JNI_OUT)

HelloJNI.h: HelloJNI.class
    javah -jni HelloJNI

$(JNI_LIB): HelloJNI.c HelloJNI.h
    gcc $(CFLAGS) -o $@  HelloJNI.c

HelloJNI.class: HelloJNI.java
    javac HelloJNI.java

run:
    java  HelloJNI
    #java -Djava.library.path=. HelloJNI

clean:
    rm $(JNI_OUT) 

When i run the java app, the OLD problem occurs:

Picked up JAVA_TOOL_OPTIONS: -Dfile.encoding=UTF8 java.library.path=.:/home/mancook/cook/work/StSoftware/src/java/StTestJni/tutor01_HelloJNI:/usr/java/packages/lib/amd64:/usr/lib64:/lib64:/lib:/usr/lib
Exception in thread "main" java.lang.UnsatisfiedLinkError: no libHelloJNI in java.library.path
at java.lang.ClassLoader.loadLibrary(ClassLoader.java:1886)
at java.lang.Runtime.loadLibrary0(Runtime.java:849)
at java.lang.System.loadLibrary(System.java:1088)
at HelloJNI.main(HelloJNI.java:22)
make: *** [run] Error 1

I have googled internet for this problem and find that it is an OLD question. But I CANNOT find any method to fix my problem!! Hope someone can help me. Thanks in advance.

1
Could you also paste your native file, the HelloJNI.c? That would make it simpler for people to reproduce this.Christian Hujer
You need the -Djava.library.path to actually include the directory that contains libHelloJNI.so.Elliott Frisch
#include <jni.h> #include <stdio.h> #include "HelloJNI.h" JNIEXPORT void JNICALL Java_HelloJNI_sayHello (JNIEnv * env, jobject thisObj) { printf("Hello Momo. This is C code."); return; }mancook
Ask a non-tech question about using this website. Can i edit my question?mancook
Yes you can edit your question. There's a grey "edit" text below your question. Everybody can edit your question. That's what StackOverflow is designed for.Christian Hujer

1 Answers

1
votes

You need -Djava.library.path=. in the Makefile, and you need to load the library with System.loadLibrary("HelloJNI"); - no lib prefix, no .so suffix. The prefix and suffix are handled by Java - think of it, naming scheme on Windows is different (stupid but fact). And beware of the pitfall that you have System.loadLibrary() twice in your code, if you change only one of them, it will still fail. That one actually had cost me a few minutes :P

P.S.: I suggest a few changes to your Makefile. I would use $(RM) instead of rm. Goals which are not files should be declared .PHONY. Variables which do not refer to automatic variables can be assigned with := instead of =. I would use a separate step for creating the .so from the .o file. I would use a pattern rule for compiling Java, like %.class: %.java. I would use a pattern rule for creating the header file, like %.h: %.class. The -I stuff should be in CPPFLAGS not CFLAGS because it's for the preprocessor. The -shared should then go into LDFLAGS and so on...

Here's your new Makefile:

CPPFLAGS:=-I"${JAVA_HOME}/include" -I"${JAVA_HOME}/include/linux"

JNI_LIB:=libHelloJNI.so
JNI_OUT:=$(JNI_LIB) HelloJNI.o HelloJNI.h HelloJNI.class
CFLAGS:=-fPIC
LDFLAGS:=-shared

.PHONY: all
all: $(JNI_OUT)

%.h: %.class
    javah -jni HelloJNI

$(JNI_LIB): HelloJNI.o
    $(LINK.o) $^ $(LOADLIBES) $(LDLIBS) -o $@

HelloJNI.o: HelloJNI.c HelloJNI.h

%.class: %.java
    javac HelloJNI.java

.PHONY: run
run:
    java -Djava.library.path=. HelloJNI

.PHONY: clean
clean:
    $(RM) $(JNI_OUT)