在Linux上运行Java调用native.so时出现持久性的不满意链接错误 我试图得到一个小的/示例java应用程序,它使用JNI调用调用本地C++代码,在Linux上运行。
我使用Eclipse构建、配置环境和运行应用程序在Linux上运行Java调用native.so时出现持久性的不满意链接错误 我试图得到一个小的/示例java应用程序,它使用JNI调用调用本地C++代码,在Linux上运行。,java,c++,linux,java-native-interface,Java,C++,Linux,Java Native Interface,我使用Eclipse构建、配置环境和运行应用程序 我把“总体”项目分成2个单独的Eclipse项目:1 java项目和1 C++项目,包含本机代码。 Java部分包括: 1:一个“main”类,从中调用一个“adapter”类来加载.so库并调用本机接口/C++方法 2:一个“适配器”类,包含本机方法声明 public class Java_Main_For_So_Kickoff { public static void main(String[] args) { /
我把“总体”项目分成2个单独的Eclipse项目:1 java项目和1 C++项目,包含本机代码。
Java部分包括: 1:一个“main”类,从中调用一个“adapter”类来加载.so库并调用本机接口/C++方法 2:一个“适配器”类,包含本机方法声明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)");
}
}
<> > C++部分由以下部分组成:
1:javah生成的*.h文件,包含本机方法定义
2:A*.CPP文件,包含本机方法的C++实现
两者都非常初级,只是为了测试JNI环境设置的健全性。在这个问题的原始帖子中添加了这个,省略了那个
.h文件:本机\u Cpp\u适配器.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适配器.h
*
*创建日期:2017年8月23日
*作者:adminuser
*/
#ifndef SRC_NATIVE_CPP_ADAPTER_H_
#定义SRC\u本机\u CPP\u适配器\u H_
/*不要编辑此文件-它是机器生成的*/
#包括
/*类本机\u Cpp\u适配器的标头*/
#ifndef包括本机Cpp适配器
#定义包含的本地Cpp适配器
#ifdef_uucplusplus
外部“C”{
#恩迪夫
JNIEXPORT void JNICALL Java\u本机\u Cpp\u适配器\u测试\u启动\u So\u打印
(JNIEnv*,jobject);
#ifdef_uucplusplus
}
#恩迪夫
#恩迪夫
#endif/*SRC_NATIVE_CPP_适配器_H_*/
.cpp文件:本机\u cpp\u适配器.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;
}
#包括“jni.h”
#包括
使用名称空间std;
JNIEXPORT void JNICALL Java\u本机\u Cpp\u适配器\u测试\u启动\u So\u打印
(JNIEnv*,jobject)
{
cout您的本机方法的名称似乎无效。请确保正确转义\u。\u用于分隔本机方法中的包。您需要遵循命名约定:
如果方法名中有“1”,则需要在本机代码中用“1”对其进行转义
例如,对于Java中的方法:
public static native void display_Message();
你需要:
JNIEXPORT void JNICALL Java_recipeNo001_HelloWorld_display_1Message
(JNIEnv *, jclass);
注意“\u 1”在“显示”和“消息”之间
来源取自(并稍作修改)此处:
更新
您应注意的地方:
如果其他所有操作都失败,请确保在运行Eclipse之前设置LD\u LIBRARY\u PATH
。这将让您了解Eclipse是玩得很糟糕还是其他东西坏了
确保在启动代码时使用“-D”传递java.library.path
。您可以在调试配置中将其设置为JVM参数
有时,这可能很棘手,结果可能是您的库根本不包含符号。您可以使用nm
nm libSomeLibFile.so
您还可以在Eclipse中设置项目的属性
配置中的本机代码位置
更新。我已经稍微简化了您的代码,以便更容易地检查错误。我建议您从类名中删除“\u1”,因为它们在本机代码中再次混淆
请看这里:
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();
}
}
本机适配器类
public class NativeCppAdapter {
public native void testKickoffSoForPrint();
public void locLoadLib() {
String soLibName = "/tmp/libNativeCppAdapter.so";
System.load(soLibName);
}
}
C++代码(注意C导出-它对函数名有影响!)
再多说几句
如果编译代码时没有
#ifdef __cplusplus
extern "C" {
#endif
...
#ifdef __cplusplus
}
#endif
库中的符号将不正确(不是JVM所期望的)
另一件事是。如果您使用“loadLibrary”,您必须确保文件名的格式为:libSomeName。因此,您可以通过System.loadLibrary(“SomeName”)加载文件
-您必须确保java.library.path
或LD_library_path
指向文件。另一方面,如果您使用System.load
,则不必对名称做任何假设。只需确保提供文件的完整路径。例如:/tmp/someFileWithMyLib
。。用于在本机方法中分隔包。您需要遵循命名约定:
如果方法名中有“1”,则需要在本机代码中用“1”对其进行转义
例如,对于Java中的方法:
public static native void display_Message();
你需要:
JNIEXPORT void JNICALL Java_recipeNo001_HelloWorld_display_1Message
(JNIEnv *, jclass);
注意“\u 1”在“显示”和“消息”之间
来源取自(并稍作修改)此处:
更新
您应注意的地方:
如果其他所有操作都失败,请确保在运行Eclipse之前设置LD\u LIBRARY\u PATH
。这将让您了解Eclipse是玩得很糟糕还是其他东西坏了
确保在启动代码时使用“-D”传递java.library.path
。您可以在调试配置中将其设置为JVM参数
有时,这可能很棘手,结果可能是您的库根本不包含符号。您可以使用nm
nm libSomeLibFile.so
您还可以在Eclipse中设置项目的属性
配置中的本机代码位置
更新。我已经稍微简化了您的代码,以便更容易地检查错误。我建议您从类名中删除“\u1”,因为它们在本机代码中再次混淆
请看这里:
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();
}
}
本机适配器类
public class NativeCppAdapter {
public native void testKickoffSoForPrint();
public void locLoadLib() {
String soLibName = "/tmp/libNativeCppAdapter.so";
System.load(soLibName);
}
}
C++代码(注意C导出-它对函数名有影响!)
再多说几句
如果编译代码时没有
#ifdef __cplusplus
extern "C" {
#endif
...
#ifdef __cplusplus
}
#endif
库中的符号将不正确(不是JVM所期望的)
另一件事是。如果您使用“loadLibrary”,您必须确保文件名的格式为:libSomeName。因此,您通过System.loadLibrary(“SomeName”);
-加载文件,并且您必须确保java.library.path
或<