简体   繁体   English

在Linux上运行Java调用本机.so时发生永久性UnsatisfiedLinkError

[英]Persistent UnsatisfiedLinkError while running Java invoking native .so on Linux

I'm trying to get a small/sample Java application, which invokes native C++ code using JNI calls, running on Linux. 我正在尝试获取一个小型/示例Java应用程序,该应用程序使用在Linux上运行的JNI调用来调用本机C ++代码。

I use Eclipse to build, configure the environment and run the application. 我使用Eclipse构建,配置环境并运行该应用程序。

I have divided the "overall" project in 2 separate Eclipse projects: 1 Java project and 1 C++ project, containing the native code. 我已将“总体”项目分为2个单独的Eclipse项目:1个Java项目和1个C ++项目,其中包含本机代码。

Eclipse project view Eclipse项目视图

The Java part consists of: 1: a "main" class, from which an "adapter" class is invoked to load the .so library and call the native interface/C++ methods 2: an "adapter" class, containing the native method declarations Java部分包括:1:一个“主”类,从中调用“ adapter”类以加载.so库并调用本机接口/ C ++方法2:一个“ adapter”类,其中包含本机方法声明

public class Java_Main_For_So_Kickoff {

    public static void main(String[] args) {
        // TODO Auto-generated method stub
        System.out.println("Hello from Java main!");

        Native_Cpp_Adapter adapter = new Native_Cpp_Adapter();

        adapter.locSetProperty();
        adapter.locLoadLib();

        adapter.sayHello();

        adapter.test_Kickoff_So_For_Print();

    }

}


public class Native_Cpp_Adapter {   
    public native void test_Kickoff_So_For_Print();

    public void locSetProperty() {
        "/home/adminuser/workspace_Unit_Test_Java_Cpp/Unit_Test_Cpp/Debug");
        String libPathProp = System.getProperty("java.library.path");

        System.out.println("lib path set:" + libPathProp);
    }

    public void locLoadLib() {
        System.setProperty("java.library.path", 
        "//home//adminuser//workspace_Unit_Test_Java_Cpp//Unit_Test_Cpp//Debug//");
        String libPathProp = System.getProperty("java.library.path");
        String soLibName = "libUnit_Test_Cpp.so";
        String soLibWithPath = libPathProp.concat(soLibName);

        System.out.println("lib path set for loading:" + libPathProp);
        System.load(soLibWithPath);

        System.out.println("library loaded");
    }

    public void sayHello() {
        System.out.println("Hello from JNI Adapter (Java part)");
    }
}

The C++ part consists of: 1: a *.h file, generated with javah, containing the native method definition 2: a *.cpp file, containing the C++ implementation of the native methods C ++部分包括:1:一个用javah生成的* .h文件,包含本机方法定义2:一个* .cpp文件,包含本机方法的C ++实现

Both very rudimentary, only meant to sanity-test the JNI environment setup. 两者都非常初级,仅意味着对JNI环境设置进行完整性测试。 Added this, omitted that in the original post for this issue. 添加了此内容,在此问题的原始帖子中省略了此内容。

.h file: Native_Cpp_adapter.h .h文件:Native_Cpp_adapter.h

     /*
 * Native_Cpp_Adapter.h
 *
 *  Created on: Aug 23, 2017
 *      Author: adminuser
 */

#ifndef SRC_NATIVE_CPP_ADAPTER_H_
#define SRC_NATIVE_CPP_ADAPTER_H_

/* DO NOT EDIT THIS FILE - it is machine generated */
#include <jni.h>
/* Header for class Native_Cpp_Adapter */

#ifndef _Included_Native_Cpp_Adapter
#define _Included_Native_Cpp_Adapter
#ifdef __cplusplus
extern "C" {
#endif

JNIEXPORT void JNICALL Java_Native_Cpp_Adapter_test_Kickoff_So_For_Print
  (JNIEnv *, jobject);


#ifdef __cplusplus
}
#endif
#endif





#endif /* SRC_NATIVE_CPP_ADAPTER_H_ */

.cpp file: Native_Cpp_Adapter.cpp .cpp文件:Native_Cpp_Adapter.cpp

#include "jni.h"
#include <iostream>

using namespace std;

JNIEXPORT void JNICALL Java_Native_Cpp_Adapter_test_Kickoff_So_For_Print
 (JNIEnv *, jobject)
{
    cout << "Correct kickoff of Native JNI method nr. 1";
    return;
}

From the C++ project an .so is built, including jni.h and jni_md.h. 从C ++项目中构建了一个.so,包括jni.h和jni_md.h。 for the Java project, the resulting .so is included as external library in the Java build path and added as VM argument "java.library.path" in the run configuration (for the applicable Java project/main class). 对于Java项目,生成的.so作为外部库包含在Java构建路径中,并作为VM参数“ java.library.path”添加到运行配置中(适用于Java项目/主类)。

First, the .so is built from the C++ project: this results in an .so binary in the C++ project folder within the common workspace. 首先,.so是从C ++项目构建的:这会在公共工作空间内的C ++项目文件夹中生成一个.so二进制文件。 The the Java build is performed. Java构建已执行。 Thereafter the Java program is run invoking the project's main class. 此后,将运行Java程序并调用项目的主类。

Result: the .so appears to be loaded, but thereafter the process is aborted with an (very persistent) "UnsatisfiedLinkError". 结果:.so似乎已加载,但是此后该过程中止,并出现(非常持久)“ UnsatisfiedLinkError”。

For what I understand, this error is thrown if the Java Virtual Machine cannot find an appropriate native-language definition of a method declared native. 据我了解,如果Java虚拟机找不到声明为native的方法的适当的本地语言定义,则会引发此错误。

This sounds like the native method definition (C++ side) is not compliant with the native method declaration on the Java-side. 这听起来像本机方法定义(C ++端)与Java端的本机方法声明不兼容。 But the C++ definitions are as far as I see/know entirely compliant with the native method declaration in Java, and with the applicable native method naming conventions. 但是据我所知/知道,C ++定义完全符合Java中的本机方法声明以及适用的本机方法命名约定。 For me, it appears that all building/configuration options are exhausted - does anyone have a suggestion what might be the cause, and to solve this? 对我而言,似乎所有的构建/配置选项都已用尽-是否有人建议可能是什么原因,并且要解决此问题?

It looks like name of your native method is not valid. 看来您的本机方法名称无效。 Make sure to properly escape _ . 确保正确逃脱_ _ is used to separate packages in native methods. _用于在本机方法中分隔软件包。 You need to follow naming convention: 您需要遵循命名约定:

https://docs.oracle.com/javase/8/docs/technotes/guides/jni/spec/design.html#resolving_native_method_names https://docs.oracle.com/javase/8/docs/technotes/guides/jni/spec/design.html#resolving_native_method_names

If you have "_" in method name, you need to escape it with "_1" in native code. 如果方法名称中包含“ _”,则需要在本机代码中使用“ _1”对其进行转义。

Example. 例。 For method in Java: 对于Java中的方法:

public static native void display_Message();

you need: 你需要:

JNIEXPORT void JNICALL Java_recipeNo001_HelloWorld_display_1Message
  (JNIEnv *, jclass);

Note " _1 " that is between " display " and " Message ". 注意在“ 显示 ”和“ 消息 ”之间的“ _1 ”。

Source taken (and slightly modified) from here: http://jnicookbook.owsiak.org/recipe-No-001/ 从此处获取(并稍作修改)的来源: http//jnicookbook.owsiak.org/recipe-No-001/

Update 更新资料

Where should you pay attention: 您应该注意的地方:

  1. If everything else fails, make sure to set LD_LIBRARY_PATH before running Eclipse. 如果其他所有操作均失败,请确保在运行Eclipse之前设置LD_LIBRARY_PATH This will give you some insight whether Eclipse plays nasty or something else is broken 这将为您提供一些有关Eclipse是否讨厌或其他问题的见解。
  2. Make sure to pass java.library.path using "-D" while starting your code. 启动代码时,请确保使用“ -D”传递java.library.path You can set it in Debug configuration as JVM arguments 您可以在Debug配置中将其设置为JVM参数
  3. Sometimes, it might be tricky, and it may turn out that your lib doesn't contain symbol at all. 有时,这可能很棘手,并且可能导致您的lib根本不包含符号。 You can check it using nm 您可以使用nm检查它

     nm libSomeLibFile.so 
  4. You can also set native code location inside project's Properties configuration in Eclipse 您还可以在Eclipse中的项目的Properties配置中设置本机代码位置

    在此处输入图片说明

Update. 更新。 I have slightly simplified your code to make it easier to check what is wrong. 我稍微简化了您的代码,使检查问题更容易。 I suggest you to remove "_" from class names as well as they are again mixed up in native code. 我建议您从类名中删除“ _”,并将它们再次混入本机代码中。

Take a look here: 在这里看看:

public class Main {

    public static void main(String[] args) {
        // TODO Auto-generated method stub
        System.out.println("Hello from Java main!");
        NativeCppAdapter adapter = new NativeCppAdapter();
        adapter.locLoadLib();
        adapter.testKickoffSoForPrint();
    }
}

Native Adapter class 本机适配器类

public class NativeCppAdapter {
    public native void testKickoffSoForPrint();

    public void locLoadLib() {
        String soLibName = "/tmp/libNativeCppAdapter.so";
        System.load(soLibName);
    }
}

C++ code (pay attention to C export - it has impact on function name !) C ++代码(注意C导出-它会影响函数名称!)

#include "jni.h"
#include <iostream>

using namespace std;

#ifdef __cplusplus
extern "C" {
#endif
/*
 * Class:     NativeCppAdapter
 * Method:    testKickoffSoForPrint
 * Signature: ()V
 */
JNIEXPORT void JNICALL Java_NativeCppAdapter_testKickoffSoForPrint
  (JNIEnv *, jobject) {

    cout << "Correct kickoff of Native JNI method nr. 1";
    return;

}

#ifdef __cplusplus
}
#endif

Compile code and Java 编译代码和Java

> javac *.java
> c++ -g -shared -fpic -I${JAVA_HOME}/include \
-I${JAVA_HOME}/include/darwin \
NativeCppAdapter.cpp \
-o /tmp/libNativeCppAdapter.so
> java -cp . Main
Hello from Java main!
Correct kickoff of Native JNI method nr. 1

Just few more remarks 再说几句话

If you compile code without 如果编译代码时没有

#ifdef __cplusplus
extern "C" {
#endif
...
#ifdef __cplusplus
}
#endif

your symbols inside library will be incorrect (not what JVM expects). 您的库中的符号将不正确(不是JVM期望的)。

Another thing is. 另一件事是。 If you use "loadLibrary" you have to make sure that file name is in the form: lib SomeName .so and you load file via System.loadLibrary("SomeName"); 如果使用“ loadLibrary”,则必须确保文件名的格式为:lib SomeName .so,然后通过System.loadLibrary("SomeName");加载文件System.loadLibrary("SomeName"); - and you have to make sure that either java.library.path or LD_LIBRARY_PATH point to the file. -并且您必须确保java.library.pathLD_LIBRARY_PATH指向该文件。 If you use System.load , on the other hand, you don't have to make any assumptions regarding name. 另一方面,如果使用System.load ,则无需对名称进行任何假设。 Just make sure you provide full path to file. 只要确保您提供文件的完整路径即可。 For example: /tmp/someFileWithMyLib 例如: /tmp/someFileWithMyLib

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

相关问题 从Java运行本机dll时,线程“主” java.lang.UnsatisfiedLinkError中的异常:Native.initiate(I)V - Exception in thread “main” java.lang.UnsatisfiedLinkError: Native.initiate(I)V while running native dll from Java Java:调用提供“线程“ main”中的异常” java.lang.UnsatisfiedLinkError的本机方法 - Java: Invoking native method giving “Exception in thread ”main“ java.lang.UnsatisfiedLinkError” 运行android本机代码导致java.lang.UnsatisfiedLinkError - Running android native code is causing java.lang.UnsatisfiedLinkError 运行分布式jar时出现java.lang.UnsatisfiedLinkError - java.lang.UnsatisfiedLinkError while running distributed jar [Linux]为JNI加载.so文件导致:java.lang.UnsatisfiedLinkError:java.library.path中没有libdebug - [Linux]Load .so file for JNI results in: java.lang.UnsatisfiedLinkError: no libdebug in java.library.path 加载本机库时出现UnsatisfiedLinkError - UnsatisfiedLinkError while loading native library 访问本机方法时出现UnsatisfiedLinkError - UnsatisfiedLinkError while accessing a Native method Linux中的java.lang.UnsatisfiedLinkError - java.lang.UnsatisfiedLinkError in Linux Linux上的java.lang.UnsatisfiedLinkError - java.lang.UnsatisfiedLinkError on Linux Java 中 DuckDb 本机代码的 UnsatisfiedLinkError - UnsatisfiedLinkError for DuckDb native code in Java
 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM