我正在学习graalvm,我想知道我是否可以使用JNI来调用java原生构建的共享库?
假设有两个Java源代码,第一个会提前用graalvm编译成共享库,第二个会运行在JVM上,它会在运行时加载第一个源代码生成的共享库。我发现这在实践中很难,因为 JNI 和 graalvm native-build 生成的头文件的签名不同。
我有什么好的方法可以做到这一点吗?
两个源码及其生成的头文件如下:
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
从两个头文件可以看出:它们的签名不兼容,而且参数的类型很难破解,因为它们都是机器生成的。
我想到的一个可能的解决方案是我可以使用另一个 C/C++ 代码作为“中间层”,然后调用堆栈可以是 JNI ==> C/C++ ==> graalvm 本机库。不过这个方案好像太复杂了,有没有更好的做法呢?