JNI / JNA 不满足 Link,但存在符号
JNI / JNA Unsatisfied Link, but symbol is present
我正在尝试通过提供的 c 库 "libext.so" 集成遗留系统。
为了测试 JNA/JNI 我想调用 "setProperty" 函数。
objdump libext.so -t | grep setProperty
0000000000104d50 g F .text 000000000000000e Java_ExtClass_setProperty
0000000000104be0 g F .text 000000000000016a Java_com_company_ExtClass_setProperty
这是我的代码,使用 java 8,jna 4.5.1 and/or 本机 jni,调用函数时两种方式都失败并显示 UnsatisfiedLinkError
- 加载库无需一个例外。
public class TestClass
{
static {
try {
System.load("/path/to/libext.so");
} catch (Throwable e) {
e.printStackTrace();
}
}
public interface CLibrary extends Library {
CLibrary INSTANCE = (CLibrary)
Native.loadLibrary(("/path/to/libext.so"), CLibrary.class);
void setProperty(String key, String value);
}
public static native synchronized void setProperty(String key, String value);
public static void main(String[] args) {
// setProperty("a", "b");
CLibrary.INSTANCE.setProperty("a", "b");
}
}
我错过了什么?
@更新:
我现在将 JNI class 和 JNA 接口移到了正确的包中并重命名了 jna 接口
包 com.company;
public interface LibExtLibrary extends Library {
LibExtLibrary INSTANCE = (LibExtLibrary)
Native.loadLibrary(("/path/to/libext.so"),
LibExtLibrary.class);
void Java_com_company_ExtClass_setProperty(String key, String value);
void Java_ExtClass_setProperty(String key, String value);
void ExtClass_setProperty(String key, String value);
void setProperty(String key, String value);
}
在 INSTANCE 上调用前两个方法得到 InvalidMemoryAccess
,后两个方法得到 UnsatisfiedLinkError
.
只要完全限定的class名称等于本机库中定义的名称,JNI 方法就会起作用
如果问题是“为什么我不能用 JNA 调用 JNI 方法?”:
为了能够从 Java 调用外部库,您必须使用 JNI。您将一些方法声明为 native
并且 javah
将为您生成特殊函数,您可以用您的代码填充这些函数。每个函数都有两个附加参数:绑定到调用 Java 线程的 env
指针和作为方法接收器的对象或 class。如果您将 Java 对象作为其他参数之一传递,您将在函数中获得 jobject
。
如果 JNI 函数的实现只包括将调用转发到另一个外部库,您也可以使用 JNA。 JNA 使用 JNI 包装 libffi 因此您可以直接调用现有的外部库。这样您就不必自己创建包装库。 JNA 不会创建 env
指针或将方法接收器作为参数传递。它将尝试将所有其他参数编组为外部库可以理解的内容。这意味着这里没有 jobject
。
总结:JNI 调用为其显式创建的函数并且参数是 Java 特定的。 JNA 在内部使用 JNI 来调用 non-Java 个外部库中的函数。
我正在尝试通过提供的 c 库 "libext.so" 集成遗留系统。 为了测试 JNA/JNI 我想调用 "setProperty" 函数。
objdump libext.so -t | grep setProperty
0000000000104d50 g F .text 000000000000000e Java_ExtClass_setProperty
0000000000104be0 g F .text 000000000000016a Java_com_company_ExtClass_setProperty
这是我的代码,使用 java 8,jna 4.5.1 and/or 本机 jni,调用函数时两种方式都失败并显示 UnsatisfiedLinkError
- 加载库无需一个例外。
public class TestClass
{
static {
try {
System.load("/path/to/libext.so");
} catch (Throwable e) {
e.printStackTrace();
}
}
public interface CLibrary extends Library {
CLibrary INSTANCE = (CLibrary)
Native.loadLibrary(("/path/to/libext.so"), CLibrary.class);
void setProperty(String key, String value);
}
public static native synchronized void setProperty(String key, String value);
public static void main(String[] args) {
// setProperty("a", "b");
CLibrary.INSTANCE.setProperty("a", "b");
}
}
我错过了什么?
@更新:
我现在将 JNI class 和 JNA 接口移到了正确的包中并重命名了 jna 接口
包 com.company;
public interface LibExtLibrary extends Library {
LibExtLibrary INSTANCE = (LibExtLibrary)
Native.loadLibrary(("/path/to/libext.so"),
LibExtLibrary.class);
void Java_com_company_ExtClass_setProperty(String key, String value);
void Java_ExtClass_setProperty(String key, String value);
void ExtClass_setProperty(String key, String value);
void setProperty(String key, String value);
}
在 INSTANCE 上调用前两个方法得到 InvalidMemoryAccess
,后两个方法得到 UnsatisfiedLinkError
.
只要完全限定的class名称等于本机库中定义的名称,JNI 方法就会起作用
如果问题是“为什么我不能用 JNA 调用 JNI 方法?”:
为了能够从 Java 调用外部库,您必须使用 JNI。您将一些方法声明为 native
并且 javah
将为您生成特殊函数,您可以用您的代码填充这些函数。每个函数都有两个附加参数:绑定到调用 Java 线程的 env
指针和作为方法接收器的对象或 class。如果您将 Java 对象作为其他参数之一传递,您将在函数中获得 jobject
。
如果 JNI 函数的实现只包括将调用转发到另一个外部库,您也可以使用 JNA。 JNA 使用 JNI 包装 libffi 因此您可以直接调用现有的外部库。这样您就不必自己创建包装库。 JNA 不会创建 env
指针或将方法接收器作为参数传递。它将尝试将所有其他参数编组为外部库可以理解的内容。这意味着这里没有 jobject
。
总结:JNI 调用为其显式创建的函数并且参数是 Java 特定的。 JNA 在内部使用 JNI 来调用 non-Java 个外部库中的函数。