I've got a package called com.example.remote in that package I have a Remote.java file with
public native static void send_feedback(String feedback);
static {
System.loadLibrary("com_example_remote_Remote");
}
then in my com_example_remote_Remote.c file I got this method:
JNIEXPORT void JNICALL Java_com_example_remote_Remote_send_feedback(JNIEnv *env, jclass clazz, jstring feedback)
Everything compiles. But when I do a call to the java function the program stops working and gives me:
12-19 12:21:31.183: E/AndroidRuntime(3196): FATAL EXCEPTION: main
12-19 12:21:31.183: E/AndroidRuntime(3196): java.lang.UnsatisfiedLinkError: Native method not found: com.example.remote.Remote.send_feedback:(Ljava/lang/String;)V
12-19 12:21:31.183: E/AndroidRuntime(3196): at com.example.remote.Remote.send_feedback(Native Method)
I think my syntax is conform the rules of JNI. I deleted the obj map once I thought maybe it would solve the problem. I rebuild the project and still gives me that error.
EDIT:
changed the name to sendFeedback and now I get this error:
12-19 12:49:26.335: A/libc(3280): Fatal signal 11 (SIGSEGV) at 0x00000cd0 (code=0), thread 3280 (.example.remote)
Add extern "C" in native method definition. i.e.
extern "C" JNIEXPORT void JNICALL Java_com_example_remote_Remote_send_feedback(JNIEnv *env, jclass clazz, jstring feedback){.......}
Or
If possible change MethodName in declaration and definition (in java file and .c file) because _ may be problem in method name. i.e.
public native static void sendFeedback(String feedback);
extern "C" JNIEXPORT void JNICALL Java_com_example_remote_Remote_sendFeedback(JNIEnv *env, jclass clazz, jstring feedback)
{
....
}
you may find a sample here
I've changed the name to sendFeedback so it's without the underscore. Also there was an error in the method what doesn't matter for this answer.
Related
First, I'm using JDK 8 32bits with Eclipse 32bits.
I'm trying to figure out how to solve this error:
java.lang.UnsatisfiedLinkError :
I checked signature's functions in C and package in JAVA but it looks right.
The complete error is :
Exception in thread "main" java.lang.UnsatisfiedLinkError:
fr.Model.initModel(Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;[I)V
Java's function:
void initModel(String, String, String, int[]) in package fr and class Model
C function:
JNIEXPORT void JNICALL Java_fr_Model_initModel (JNIEnv *, jobject, jstring, jstring, jstring, jintArray);
Launching it in a separate JVM but it does find the .dll. All dependencies checked, they are in system32.
Already doing the extern "C" { ... } trick to deal with C++.
Any ideas?
I have a repo with two simple implementations for JNI with C/C++.
I have the java.lang.UnsatisfiedLinkError error for C++ static JNI method.
(base) GlushenkovYuri:java y.glushenkov$ /Library/Java/JavaVirtualMachines/jdk1.8.0_191.jdk/Contents/Home/bin/java -Djava.library.path=. MyJNIExample
Hello World from C!
Exception in thread "main" java.lang.UnsatisfiedLinkError: MyJNIExample.sayHelloCpp()V
at MyJNIExample.sayHelloCpp(Native Method)
at MyJNIExample.main(MyJNIExample.java:51)
But for C native method the same approach work well.
For C++ works without static.
You can reproduce the same behaviour in the following way:
1) Uncomment lines with the static native method for C++ and this one. And comment lines with the NON static native method for C++ and this one;
2) And just perform the next steps described in my README.md file;
Can somebody explain to me why the native method static/non static works for C, but only the native NON static method works for C++?
UPD: my header file
/* DO NOT EDIT THIS FILE - it is machine generated */
#include <jni.h>
/* Header for class MyJNIExample */
#ifndef _Included_MyJNIExample
#define _Included_MyJNIExample
#ifdef __cplusplus
extern "C" {
#endif
/*
* Class: MyJNIExample
* Method: sayHelloC
* Signature: ()V
*/
JNIEXPORT void JNICALL Java_MyJNIExample_sayHelloC
(JNIEnv *, jclass);
/*
* Class: MyJNIExample
* Method: sayHelloCpp
* Signature: ()V
*/
JNIEXPORT void JNICALL Java_MyJNIExample_sayHelloCpp
(JNIEnv *, jclass);
#ifdef __cplusplus
}
#endif
#endif
The type of the function that javah generates differs according to whether the native method is static or not:
JNIEXPORT void JNICALL Java_MyJNIExample_sayHelloCppstatic
(JNIEnv *, jclass);
JNIEXPORT void JNICALL Java_MyJNIExample_sayHelloCppnonstatic
(JNIEnv *, jobject);
In addition, the generated header contains an extern "C" declaration to make sure the compiler keeps the name intact of mangling it like __Z29Java_MyJNIExample_sayHelloCppP7JNIEnv_P8_jobject.
So, what happened here is that you generated a header file with a static native void sayHelloCpp, so there is an extern "C" declaration for the function with signature (JNIEnv *, jclass), but you provide a (JNIEnv *, jobject) function. The compiler uses its default mangling scheme as the signature does not match, and the Java runtime fails to find it.
So, long story short: always regenerate your header file and check C++ function signatures if you change your Java class. I could not reproduce your issue because I wrote a Makefile that always regenerated the header file after recompiling the Java file.
I have an Android project with a Java base Activity, Java JNI interface class, and native code. I have the proper
System.loadlibrary(_libraryname_);
In my Java interface class and from the logcat output:
11-29 15:11:20.737: D/dalvikvm(8940): No JNI_OnLoad found in /data/data/com.example.testjni/lib/libTestJNI.so 0x406ef030, skipping init
In my cpp file header:
extern "C" {
JNIEXPORT jint JNICALL JNIOnLoad(JavaVM *, void *);
}
In the cpp file:
JNIEXPORT jint JNICALL JNIOnLoad(JavaVM *vm, void *reserved)
{
LOGI("JNIOnLoad");
jvm = vm;
return JNI_VERSION_1_6; /* the required JNI version */
}
But still the OnLoad function never is called. I've tried uninstalling the app and re-installing it but it never runs.
Function signature is JNI_OnLoad. There is an underscore / _ between JNI and OnLoad.
I have this java method:
public static native void processBuffer(ByteBuffer bb);
with javah
JNIEXPORT void JNICALL Java_com_lan_factorial_IssmJni_processBuffer
(JNIEnv *env, jclass klass , jobject buf)
work perfectly
with Jni onload
static JNINativeMethod method_table[] = {
{"fac" , "(J)J" , (void *) factorial},
{"getBuffer", "()[D" , (void *) getBufferNative},
//{"processBuffer", "(Ljava/nio/ByteBuffer)V", (void *) fillBuffer}};
The others method in this table works, exept the last one which correspond to the method generate from javah above. And of course if I do JNI onload i will have a method call fillBuffer.
Can someone explain why javah works but not jni_onload. Did I do something wrong?
I have other methods using jni_onload so I want to stay away from javah.
Thanks
You have a missing semicolon in the method signature. It doesn't 'correspond' at all. Don't guess at native method signatures: use the output of javap -s. Cut and paste.
I've been looking for 2 days now and no solution could help me, so here we go again:
How to fix the UnsatisfiedLinkError... in JNI?
So here's my java code:
package org.lingenio.util;
import java.util.*;
public class PTAPIWrapperForOmegaT {
private native String translateWithPTAPI(String sentence);
private native void test();
public PTAPIWrapperForOmegaT(String sentence) throws Exception{
System.out.println(sentence);
test();
}
static {
System.load("C:/Users/michael/Desktop/OmegaT/OmegaT2.3_src/native/PTAPIWrapperForOmegaT.dll");
}
}
And here's my C++ Code:
#include <iostream>
#include <windows.h>
#include <jni.h>
#include "PTAPIWrapperForOmegaT.h"
using namespace std;
JNIEXPORT jstring JNICALL Java_PTAPIWrapperForOmegaT_translateWithPTAPI(JNIEnv *env, jobject obj, jstring sentence)
{
/* stuff */
}
JNIEXPORT void JNICALL Java_PTAPIWrapperForOmegaT_test(JNIEnv *, jobject)
{
cout << "This comes from PTAPIWrapperForOmegaT.cpp test();" << endl;
}
int main(){
return 0;
}
And the header file:
/* DO NOT EDIT THIS FILE - it is machine generated */
#include <jni.h>
/* Header for class PTAPIWrapperForOmegaT */
#ifndef _Included_PTAPIWrapperForOmegaT
#define _Included_PTAPIWrapperForOmegaT
#ifdef __cplusplus
extern "C" {
#endif
/*
* Class: PTAPIWrapperForOmegaT
* Method: translateWithPTAPI
* Signature: (Ljava/lang/String;)Ljava/lang/String;
*/
JNIEXPORT jstring JNICALL Java_PTAPIWrapperForOmegaT_translateWithPTAPI
(JNIEnv *, jobject, jstring);
/*
* Class: PTAPIWrapperForOmegaT
* Method: test
* Signature: ()V
*/
JNIEXPORT void JNICALL Java_PTAPIWrapperForOmegaT_test
(JNIEnv *, jobject);
#ifdef __cplusplus
}
#endif
#endif
and how I build it:
call g++ -Wl,--add-stdcall-alias -c -DBUILDING_EXAMPLE_DLL -I G:/Software/Java/jdk1.7.0_01/include -I G:/Software/Java/jdk1.7.0_01/include/win32 PTAPIWrapperForOmegaT.cpp
call g++ -shared -Wl,-kill-at -o PTAPIWrapperForOmegaT.dll -I G:/Software/Java/jdk1.7.0_01/include -I G:/Software/Java/jdk1.7.0_01/include/win32 PTAPIWrapperForOmegaT.cpp
and finally, the error:
10211: Error: Uncatched exception in thread [Thread-14]
10211: Error: java.lang.UnsatisfiedLinkError: org.lingenio.util.PTAPIWrapperForOmegaT.test()V
10211: Error: at org.lingenio.util.PTAPIWrapperForOmegaT.test(Native Method)
10211: Error: at org.lingenio.util.PTAPIWrapperForOmegaT.<init>(PTAPIWrapperForOmegaT.java:13)
10211: Error: at org.omegat.core.machinetranslators.LingenioTranslate.translate(LingenioTranslate.java:32)
10211: Error: at org.omegat.core.machinetranslators.BaseTranslate.getTranslation(BaseTranslate.java:64)
10211: Error: at org.omegat.gui.exttrans.MachineTranslateTextArea$FindThread.search(MachineTranslateTextArea.java:122)
10211: Error: at org.omegat.gui.exttrans.MachineTranslateTextArea$FindThread.search(MachineTranslateTextArea.java:102)
10211: Error: at org.omegat.gui.common.EntryInfoSearchThread.run(EntryInfoSearchThread.java:85)
I don't know exactly about these two lines of g++ here, I think the second one would be sufficient, but some tutorial must have offered the other line as well and I kept it.
I'm on Windows 7, using MingW and the latest Java (1.7xxx I believe).
Any help is appreciated, I suspect the error lies in the compilation, but I just don't know how to go on from here.
EDIT:
Looking into the dll with DependencyWalker I can see the functions are named like I named them in the .cpp file. Of course I am calling them from the Java Wrapper with their respective names, i.e. test(). Could that be a problem? Can someone who used JNI often in the past tell me whether this is the correct way?
Turns out all the code is fine. Actually I did make mistakes compiling the header files. You can see if you look at the header files' function names, i.e.:
JNIEXPORT jstring JNICALL Java_PTAPIWrapperForOmegaT_translateWithPTAPI
(JNIEnv *, jobject, jstring);
Now, take a look at your Java files' package membership, in my case:
package org.lingenio.util;
Because I did compile the header file the wrong way, JNI was later not able to find the symbols it was looking for, because it was actually looking for this:
JNIEXPORT jstring JNICALL Java_org_lingenio_util_PTAPIWrapperForOmegaT_translateWithPTAPI(JNIEnv *env, jobject obj, jstring sentence)
So, good luck to the people out there dangling with the same problems. I'm obviously not the greatest Java programmer, that's why I had to worry about this for so long. I should have compiled my header files in the correct way in the first place.
Check your package and classpath!