I am learning graalvm, and I was wondering if it is possible that I can use JNI to call a java native-built shared library?
Let's say there are two Java source codes, the first would be compiled as a shared library ahead of time with graalvm, and the second one would be run on JVM, which would load the shared library generated by the first source code in runtime. I find this difficult in practice since the header files generated by JNI and graalvm native-build are different in their signature.
Is there any good way I can do this?
The two source codes and their generated header files are as follows:
LibEnvMap.java:
import org.graalvm.nativeimage.IsolateThread;
import org.graalvm.nativeimage.c.function.CEntryPoint;
public class LibEnvMap {
//NOTE: this class has no main() method
@CEntryPoint(name = "Java_Main_HelloWorld")
private static int HelloWorld(IsolateThread thread, Object object){
System.out.println("Hello Native World!");
return 0;
}
}
#ifndef __LIBENVMAP_H
#define __LIBENVMAP_H
#include <graal_isolate.h>
#if defined(__cplusplus)
extern "C" {
#endif
int filter_env(graal_isolatethread_t*, char*);
#if defined(__cplusplus)
}
#endif
#endif
Main.java:
public class Main {
static {
System.load("/Users/nealshinoda/Repos/HelloWorld/out/production/HelloWorld/LibEnvMap.dylib");
}
private native int HelloWorld();
public static void main(String[] args) {
System.out.println("Hello world!");
new Main().HelloWorld();
}
}
/* DO NOT EDIT THIS FILE - it is machine generated */
#include <jni.h>
/* Header for class Main */
#ifndef _Included_Main
#define _Included_Main
#ifdef __cplusplus
extern "C" {
#endif
/*
* Class: Main
* Method: HelloWorld
* Signature: ()I
*/
JNIEXPORT jint JNICALL Java_Main_HelloWorld
(JNIEnv *, jobject);
#ifdef __cplusplus
}
#endif
#endif
As you can see from the two header files: their signatures are incompatible and it is difficult to hack the type of the parameter since they are all machine-generated.
One potential solution that comes to my mind is that I could use another C/C++ code as a "middle layer", and then the call stack could be JNI ==> C/C++ ==> graalvm native library. However, this solution seems too complicated, and is there any better practice?