Я использую Python и Py4J для тестирования кода JNI. Но когда я вызываю код JNI, я получаю следующую ошибку:
py4j.protocol.Py4JJavaError: An error occurred while calling o37.createInstance.
: java.lang.UnsatisfiedLinkError: com.mgr_api_JNI.createInstance(Lcom/mgr_api_types$EDisplayType;Ljava/lang/String;Lcom/mgr_api_types$ECommType;Ljava/lang/String;)V
at com.mgr_api_JNI.createInstance(Native Method)
at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.base/java.lang.reflect.Method.invoke(Method.java:566)
at py4j.reflection.MethodInvoker.invoke(MethodInvoker.java:244)
at py4j.reflection.ReflectionEngine.invoke(ReflectionEngine.java:357)
at py4j.Gateway.invoke(Gateway.java:282)
at py4j.commands.AbstractCommand.invokeMethod(AbstractCommand.java:132)
at py4j.commands.CallCommand.execute(CallCommand.java:79)
at py4j.GatewayConnection.run(GatewayConnection.java:238)
at java.base/java.lang.Thread.run(Thread.java:834)
Я просмотрел эти ссылки ссылка 1 , ссылка 2 , ссылка 3 , ссылка 4 , ссылка 5 и ссылка 6 , плюс другие, но ни одна из них не решает мою проблему.
код
mgr_api_JNI.java:
package com;
import com.mgr_api_types.*;
public class mgr_api_JNI
{
static
{
try
{
System.loadLibrary("Mngr"); // Use "-Djava.library.path=[path to library]" option to load this library
}
catch (UnsatisfiedLinkError e)
{
System.err.println("Native code library 'Mngr' failed to load.\n" + e);
}
}
public native void createInstance(com.mgr_api_types.EDisplayType displayType,
String displaySerialNumber,
com.mgr_api_types.ECommType commType,
String portName);
}
testsJNI.java:
import com.*;
import py4j.GatewayServer;
public class testsJNI
{
public static void main(String args[])
{
testsJNI testApp = new testsJNI();
// Py4J server
GatewayServer server = new GatewayServer(testApp);
server.turnLoggingOff();
server.start();
}
}
com_mgr_api_JNI.h (создается с помощью javac -h в mgr_api_JNI.java):
/* DO NOT EDIT THIS FILE - it is machine generated */
#include <jni.h>
/* Header for class com_mgr_api_JNI */
#ifndef _Included_com_mgr_api_JNI
#define _Included_com_mgr_api_JNI
#ifdef __cplusplus
extern "C" {
#endif
/*
* Class: com_mgr_api_JNI
* Method: createInstance
* Signature: (Lcom/mgr_api_types/EDisplayType;Ljava/lang/String;Lcom/mgr_api_types/ECommType;Ljava/lang/String;)V
*/
JNIEXPORT void JNICALL Java_com_mgr_1api_1JNI_createInstance
(JNIEnv *, jobject, jobject, jstring, jobject, jstring);
#ifdef __cplusplus
}
#endif
#endif
com_mgr_api_JNI.cpp:
#include "com_mgr_api_JNI.h"
static manager::CManagerApi* manager = NULL;
JNIEXPORT void JNICALL Java_com_mgr_1api_1JNI_createInstance(
JNIEnv *env,
jobject thisObj,
jobject displayType,
jstring displaySerialNumber,
jobject commType,
jstring portName)
{
manager::EDisplayType dType = convertObjectToDisplayType(env, displayType);
const char* serialNumber = env->GetStringUTFChars(displaySerialNumber, 0);
manager::ECommType comm = convertObjectToCommType(env, commType);
const char* port = env->GetStringUTFChars(portName, 0);
char buf[100];
sprintf(buf,"%s",port);
std::string portStr = buf;
sprintf(buf,"%s",serialNumber);
std::string serialNumStr = buf;
if (manager == NULL)
{
manager = manager::CManagerApi::get();
manager->initialize(dType, serialNumStr, comm, portStr);
}
// Release memory
env->ReleaseStringUTFChars(displaySerialNumber, serialNumber);
env->ReleaseStringUTFChars(portName, port);
}
Выполнение командной строки кода Java:
java -cp /mnt/c/Workspace/library/java/:.:/home/fred/.local/share/py4j/py4j0.10.7.jar -Djava.library.path=/mnt/c/Workspace/build/library/ testsJNI
Выполнение -XshowSettings:properties
показывает следующие свойства:
awt.toolkit = sun.awt.X11.XToolkit
file.encoding = UTF-8
file.separator = /
java.awt.graphicsenv = sun.awt.X11GraphicsEnvironment
java.awt.printerjob = sun.print.PSPrinterJob
java.class.path = /mnt/c/Workspace/library/java/
.
/home/fred/.local/share/py4j/py4j0.10.7.jar
java.class.version = 55.0
java.home = /usr/lib/jvm/java-11-openjdk-amd64
java.io.tmpdir = /tmp
java.library.path = /mnt/c/Workspace/build/library/
попытки решить проблему
Убедитесь, что у меня есть действительная нативная библиотека
Выполнение ls
на java.library.path /mnt/c/Workspace/build/library/
показывает библиотеку libMngr.so
.
Если я удаляю libMngr.so
из этого места и затем пытаюсь запустить Java, он жалуется, что не может найти библиотеку.
Выполнение команды nm
на libMngr.so
показывает следующее:
000000000021f269 T Java_com_mgr_1api_1JNI_createInstance
Так что Java может найти нативную библиотеку, и в ней есть символ функции.
Выполнение команды objdump
:
$objdump -f build/library/libMngr.so
build/library/libMngr.so: file format elf64-x86-64
architecture: i386:x86-64, flags 0x00000150:
HAS_SYMS, DYNAMIC, D_PAGED
start address 0x000000000018aee0
Показывает, что собственная библиотека является 64-битной, и в соответствии с -XshowSettings:properties
я использую 64-битную Java.
Я даже поместил оператор печати прямо перед System.loadLibrary("Mngr");
в mgr_api_JNI.java
, чтобы убедиться, что собственная библиотека загружается только один раз.
Обновление
Я восстановил заголовочный файл из mgr_api_JNI.java
и скопировал объявление функции в файл .cpp
, чтобы убедиться, что имя функции указано правильно. Но я все еще получаю ту же ошибку.
Убедиться, что у меня есть допустимые классы Java
Если я сделаю ls
на java.class.path /mnt/c/Workspace/library/java/
, я найду все классы Java при компиляции mgr_api_JNI.java
.
Если я удаляю классы и пытаюсь запустить Java, то Java жалуется, что не может найти классы.
Выполнение grep -r createInstance
на java.class.path /mnt/c/Workspace/library/java/
возвращает:
Binary file com/mgr_api_JNI.class matches
com/mgr_api_JNI.java: public native void createInstance(com.mgr_api_types.EDisplayType displayType,
Таким образом, Java может найти скомпилированный класс Java и в нем есть метод createInstance
.
Вопросы
Мне кажется, что Java может найти все необходимые классы и нативную библиотеку, но я все еще получаю ошибку UnsatisfiedLinkError
.
Почему я все еще получаю эту ошибку?
Что мне нужно сделать, чтобы помочь Java найти / распознать метод createInstance
?