- iOS/Objective-C 元类和类别
- objective-c - -1001 错误,当 NSURLSession 通过 httpproxy 和/etc/hosts
- java - 使用网络类获取 url 地址
- ios - 推送通知中不播放声音
我正在使用 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)
我查看了这些链接 link 1 、 link 2 、 link 3 、 link 4 、 link 5 和 link 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(通过在 mgr_api_JNI.java 上使用 javac -h 创建):
/* 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/
在 java.library.path /mnt/c/Workspace/build/library/
上执行 ls
显示库 libMngr.so
.
如果我从该位置删除 libMngr.so
,然后尝试运行 Java,则会提示找不到该库。
在 libMngr.so
上执行 nm
命令显示以下内容:
000000000021f269 T Java_com_mgr_1api_1JNI_createInstance
所以Java可以找到native library,它有函数的符号。
执行 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
显示 native 库是 64 位的,根据 -XshowSettings:properties
我使用的是 64 位 Java。
我什至在 mgr_api_JNI.java
中的 System.loadLibrary("Mngr");
之前放置了一条打印语句,以确保只加载一次 native 库.
我已经从 mgr_api_JNI.java
重新生成头文件并将函数声明复制到 .cpp
文件以确保函数名称是正确的。但我仍然遇到同样的错误。
如果我在 java.class.path /mnt/c/Workspace/library/java/
上执行 ls
,我会从编译中找到所有 Java 类 mgr_api_JNI.java
。
如果我删除这些类并尝试运行 Java,那么 Java 会提示找不到这些类。
在 java.class.path /mnt/c/Workspace/library/java/
上执行 grep -r createInstance
返回:
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 可以找到所有需要的类和 native 库,但我仍然收到 UnsatisfiedLinkError
错误。
为什么我仍然收到此错误?
我需要做什么来帮助 Java 找到/识别 createInstance
方法?
最佳答案
这是你的错误
你有库文件:/mnt/c/Workspace/build/library/libMgr.so
但你在代码中加载了这个文件:System.loadLibrary("Mngr");
- 你打错了
您可以确保在名称正确的情况下它按预期工作
当您“离开”初始 JVM
时,-Djava.library.path
不再是向其他 JVM 提供信息的有效位置。我不知道 py4j.GatewayConnection
的详细信息,但最好确保您不运行另一个 JVM
实例,或者您不使用 JNI
那里。
我建议进行以下测试:
将 LD_LIBRARY_PATH
设置为您的库所在的位置
确保您可以仅使用public class mgr_api_JNI
(没有 Python 桥接引擎)访问代码中的库
如果您的第二个 JVM 有可能正在加载 native 代码(但找不到它),请尝试使用 _JAVA_OPTIONS=-Djava.library.path=[path to library]
。这样,所有 JVM
都会“看到”该位置 - 但您应该这样做只是为了测试目的
从另一个进程加载 lib 看起来确实有问题。如果我将您的代码缩减为如下内容:
.
|-- Makefile
|-- README.md
|-- c
| `-- com_mgr_api_JNI.cc
|-- java
| `-- com
| |-- mgr_api_JNI.java
| `-- mgr_api_types
| |-- ECommType.java
| `-- EDisplayType.java
|-- lib
`-- target
和代码本身
com_mgr_api_JNI.cc
#include <iostream>
#include "jni.h"
#include "com_mgr_api_JNI.h"
using namespace std;
JNIEXPORT void JNICALL Java_com_mgr_1api_1JNI_createInstance
(JNIEnv *env, jobject cls, jobject a, jstring b, jobject c, jstring d) {
cout << "Hello";
}
java/com/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);
public static void main(String [] arg) {
mgr_api_JNI obj = new mgr_api_JNI();
obj.createInstance(new com.mgr_api_types.EDisplayType(), "", new com.mgr_api_types.ECommType(), "");
}
}
java/com/mgr_api_types/ECommType.java
package com.mgr_api_types;
public class ECommType { }
cat java/com/mgr_api_types/EDisplayType.java
package com.mgr_api_types;
public class EDisplayType { }
然后我构建代码
Makefile.common
ARCH=$(shell uname -s | tr '[:upper:]' '[:lower:]')
ifeq ($(ARCH),darwin)
EXT=dylib
else
EXT=so
endif
生成文件
include Makefile.common
all: compilejava compilec
compilec:
c++ -std=c++11 -g -shared -fpic -I${JAVA_HOME}/include -I${JAVA_HOME}/include/$(ARCH) c/com_mgr_api_JNI.cc -o lib/libMngr.$(EXT)
compilejava:
$(JAVA_HOME)/bin/javac -h c -d target -cp target java/com/mgr_api_types/EDisplayType.java
$(JAVA_HOME)/bin/javac -h c -d target -cp target java/com/mgr_api_types/ECommType.java
$(JAVA_HOME)/bin/javac -h c -d target -cp target java/com/mgr_api_JNI.java
test:
$(JAVA_HOME)/bin/java -Djava.library.path=$(LD_LIBRARY_PATH):./lib -cp target com.mgr_api_JNI
clean:
-rm -rfv target/*
-rm c/*.h
-rm -rf lib/*
它按预期工作
make test
/Library/Java/JavaVirtualMachines/jdk-12.0.1.jdk/Contents/Home/bin/java -Djava.library.path=:./lib -cp target com.mgr_api_JNI
Hello
我认为你有这样一种情况,你的类是从另一个 JVM 实例,或者从通过 JNI 调用的东西,或者从另一个进程调用的,而你的 -Djava.library.path
不见了。
此外,尝试使用 System.load("full/path/of/library.so")
确保您可以从 JVM
访问该库。
关于java.lang.UnsatisfiedLinkError 即使库和类有方法,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/56507951/
我想了解 Ruby 方法 methods() 是如何工作的。 我尝试使用“ruby 方法”在 Google 上搜索,但这不是我需要的。 我也看过 ruby-doc.org,但我没有找到这种方法。
Test 方法 对指定的字符串执行一个正则表达式搜索,并返回一个 Boolean 值指示是否找到匹配的模式。 object.Test(string) 参数 object 必选项。总是一个
Replace 方法 替换在正则表达式查找中找到的文本。 object.Replace(string1, string2) 参数 object 必选项。总是一个 RegExp 对象的名称。
Raise 方法 生成运行时错误 object.Raise(number, source, description, helpfile, helpcontext) 参数 object 应为
Execute 方法 对指定的字符串执行正则表达式搜索。 object.Execute(string) 参数 object 必选项。总是一个 RegExp 对象的名称。 string
Clear 方法 清除 Err 对象的所有属性设置。 object.Clear object 应为 Err 对象的名称。 说明 在错误处理后,使用 Clear 显式地清除 Err 对象。此
CopyFile 方法 将一个或多个文件从某位置复制到另一位置。 object.CopyFile source, destination[, overwrite] 参数 object 必选
Copy 方法 将指定的文件或文件夹从某位置复制到另一位置。 object.Copy destination[, overwrite] 参数 object 必选项。应为 File 或 F
Close 方法 关闭打开的 TextStream 文件。 object.Close object 应为 TextStream 对象的名称。 说明 下面例子举例说明如何使用 Close 方
BuildPath 方法 向现有路径后添加名称。 object.BuildPath(path, name) 参数 object 必选项。应为 FileSystemObject 对象的名称
GetFolder 方法 返回与指定的路径中某文件夹相应的 Folder 对象。 object.GetFolder(folderspec) 参数 object 必选项。应为 FileSy
GetFileName 方法 返回指定路径(不是指定驱动器路径部分)的最后一个文件或文件夹。 object.GetFileName(pathspec) 参数 object 必选项。应为
GetFile 方法 返回与指定路径中某文件相应的 File 对象。 object.GetFile(filespec) 参数 object 必选项。应为 FileSystemObject
GetExtensionName 方法 返回字符串,该字符串包含路径最后一个组成部分的扩展名。 object.GetExtensionName(path) 参数 object 必选项。应
GetDriveName 方法 返回包含指定路径中驱动器名的字符串。 object.GetDriveName(path) 参数 object 必选项。应为 FileSystemObjec
GetDrive 方法 返回与指定的路径中驱动器相对应的 Drive 对象。 object.GetDrive drivespec 参数 object 必选项。应为 FileSystemO
GetBaseName 方法 返回字符串,其中包含文件的基本名 (不带扩展名), 或者提供的路径说明中的文件夹。 object.GetBaseName(path) 参数 object 必
GetAbsolutePathName 方法 从提供的指定路径中返回完整且含义明确的路径。 object.GetAbsolutePathName(pathspec) 参数 object
FolderExists 方法 如果指定的文件夹存在,则返回 True;否则返回 False。 object.FolderExists(folderspec) 参数 object 必选项
FileExists 方法 如果指定的文件存在返回 True;否则返回 False。 object.FileExists(filespec) 参数 object 必选项。应为 FileS
我是一名优秀的程序员,十分优秀!