Я пытаюсь вызвать функцию JNI C в исполняемом файле, на котором размещена JVM. Я скомпилирован с -rdynamic и подтвердил с помощью nm -D, что символ экспортируется в таблицу динамических символов. Однако, когда я называю это, JVM жалуется, что символ не может быть найден.
Я делал это в прошлом с LuaJIT, и это было довольно тривиально, я был бы очень удивлен, если это невозможно сделать с Java.
Я создал тестовый метод в классе JNITest
public static native int strLen();
И реализация:
#include <jni.h>
#include <java/com_jnitest_JNITest.h>
#include <string>
#include <iostream>
JNIEXPORT jint JNICALL Java_com_jnitest_JNITest_strLen(JNIEnv* env, jclass clazz)
{
return 1111;
}
int main()
{
JNIEnv* env;
JavaVM* jvm;
JavaVMInitArgs args;
JavaVMOption options[1];
args.version = JNI_VERSION_1_8;
args.nOptions = 1;
args.options = options;
args.ignoreUnrecognized = false;
std::string classpath = "-Djava.class.path=";
classpath += "/var/projects/jnitest/src/java";
options[0].optionString = (char*)classpath.c_str();
jint result = JNI_CreateJavaVM(&jvm, (void**)&env, &args);
if (result != JNI_OK) {
std::cerr << "Could not create JVM" << std::endl;
return 1;
}
jclass main_class = env->FindClass("com/jnitest/JNITest");
if (main_class == nullptr) {
std::cerr << "Could not find JNITest class" << std::endl;
return 1;
}
jmethodID main_method = env->GetStaticMethodID(main_class, "main", "()V");
// Call JNITest.main() transferring control to Java
env->CallStaticVoidMethod(main_class, main_method, nullptr);
if(env->ExceptionCheck()) {
env->ExceptionDescribe();
return 1;
}
jvm->DestroyJavaVM();
return 0;
}
JVM регистрирует все функции внутри общей библиотеки, если загружается System.loadLibrary().
Поскольку вы создаете JVM внутри своей программы, он не знает об этой функции, вы можете использовать env-> RegisterNatives (...) для связывания собственных методов с вашим классом java.
Также JNIEXPORT
не требуется, потому что вы регистрируете его с помощью указателя на функцию, и нет необходимости делать этот метод доступным извне.