Linux环境下,java调用C/C++动态库

目录

一、环境准备

1、安装gcc/g++

2、下载jdk库并配置运行环境

二、配合Java程序创建C++程序的动态库

1、生成要求清单

2、交给C++ 去实现

(1) 接口函数实现

(2) 创建动态库

(3) 检查动态库是否正常链接

3、测试:Java程序调用C++动态库


参考文章:Linux环境下,java调用C/C++动态库

一、环境准备

既然是同时需要用到 java 和 C/C++,java 的运行环境和编译C++ 的编译器自然就需要事先准备好

1、安装gcc/g++

# 安装gcc
sudo apt-get install gcc

# 安装g++
sudo apt-get install g++

2、下载jdk库并配置运行环境

jdk 是java依赖的软件工具包,运行java程序必不可少的要素。安装流程参考:JDK1.8

注意:记一下jdk的安装路径,下面要用

二、配合Java程序创建C++程序的动态库

Java程序调用的函数接口,是java程序决定的(比如函数名、形参、返回值)。C++只负责去实现,然后打包成动态库提供给Java。关于这个流程,可以这么理解:

  • Java 提供要求清单(接口函数的声明)
  • 交给C++去实现
  • C++实现以后,Java调用C++生成的动态库

1、生成要求清单(Windows环境下操作)

生成要求清单,其实就是C++可以识别的接口函数的声明(.h文件),接口函数的声明会携带项目路径的一部分,为了和Windows下保持一致,我们需要先在Windows环境下生成 .h 文件。

(1) 设计Java接口

假设Java要调用的函数接口如下:

public class SVM {
    // Java 告诉C++:你帮我实现下面这个函数
    // native关键字不可省略
	public native int svm_dll_export(double[] random, String savepath);    
}

写好以后,下面我们要把清单转变成C++认识的模样,即.h文件。

(2) 转换Java接口

先找到 SVM.java 在本地的存储位置。 

打开该路径下的命令行窗口

输入生成命令:javac -h ./ SVM.java    ( ./ 和 SVM.java之间有一个空格)

注意:只要是一个普通类就可以,不需要加任何注释!不然会报错

成功以后,可以在SVM.java同目录下看到生成的 .h 文件

2、交给C++ 去实现(Linux环境下操作)

(1) 接口函数实现

首先我们需要创建一个 SVM_DLL.cpp 文件,这个文件里放的是,上述接口函数的定义。这里可以把声明和定义分离,也可以放在一起,这里为了方便,就把声明和定义放在一起

第一步,把刚刚上面生成的 com_example_demo_utils_algorithm_SVM.h 中的内容拷贝到 SVM_DLL.cpp 中。(或者将 com_example_demo_utils_algorithm_SVM.h 上传到Linux平台然后改名为 SVM_DLL.cpp)

第二步,开始实现接口逻辑。jdoubleArray、jstring 是 jni 库提供的类型,是兼容java和C++数据类型的关键。我们要将 jdoubleArray 转换成 C++可以识别的类型。

基本类型的转化可以参考:jni基本类型的转换

jsstring / jdoubleArray类型的转换可以参考:jstring / jdoubleArray类型的转换

(2) 创建动态库

把实现上述代码逻辑时要用到的 .h 文件和 .c 文件放到同一个文件夹下。编写makefile,方便一键生成。

CC=g++              # 如果使用的是C,这里就是gcc;如果是C++,这里就是g++    
TARGET=libsvm.so    # 目标动态库文件
# 生成动态库所依赖的目标文件
TMPTARGET=SVM_DLL.o vacTestAcc.o vacSvmUtiles.o vacSvmClassify.o vacGetSampEn.o   
# 生成动态库需要的第三方头文件的搜索路径
COND=-std=c++11 \
	 -I/usr/local/java/jdk1.8.0_351/include/ \          # jdk安装目录下:jni.h(必须要有)
	 -I/usr/local/java/jdk1.8.0_351/include/linux/ \    # jdk安装目录下:jni_md.h(必须有)
	 -I/usr/local/include/eigen-3.3.9/ \              # 逻辑实现所需的第三方库目录(非必须)
	 -fpermissive     #(非必须)

$(TARGET):$(TMPTARGET)
	$(CC) -shared -o $@ $^ $(COND)
	rm $(TMPTARGET)            # 移除 .o 文件

%.o: %.cpp                             # 等价于下面的写法
	$(CC) -fPIC -c $< $(COND) 
#SVM_DLL.o:SVM_DLL.cpp                 # 下面的.cpp文件都是逻辑实现要用到的,等价于上面的写法
#	$(CC) -fPIC -o $(@) -c $^ $(COND)  
#vacTestAcc.o:vacTestAcc.cpp
#	$(CC) -fPIC -o $(@) -c $^ $(COND)
#vacGetSampEn.o:vacGetSampEn.cpp
#	$(CC) -fPIC -o $(@) -c $^ $(COND)
#vacSvmClassify.o:vacSvmClassify.cpp
#	$(CC) -fPIC -o $(@) -c $^ $(COND)
#vacSvmUtiles.o:vacSvmUtiles.cpp
#	$(CC) -fPIC -o $(@) -c $^ $(COND):

.PHONY:clean test
clean:
	rm $(TARGET)

在命令行输入:make。之后就会自动打包生成动态库。

(3) 检查动态库是否正常链接

输入 ldd -r 动态库名称 可以检查动态库的链接状况。这里我们输入:ldd -r libsvm.so

正常情况下:

异常情况下:

出现异常情况的原因大致有两种:

a. xx.cpp文件存在报错

        至于是哪个文件报错,可以输入“ c++filt 符号名 ”来确定是哪里出了问题,这里的符号名指的是_ZN10vacTestAcc16vacTestSampEnAccEPdiPKc

b. 逻辑实现时,某个要用的 .cpp 文件没有被编译生成 .o 文件。此时请检查 .o 文件是否有遗漏

3、Java程序调用C++动态库

我们回到 Java 程序,Java调用动态库里的函数之前,需要先加载动态库。基本流程如下:

  • 加载动态库。System.load("动态库所在路径")
  • 调用库函数。
public class SVM {
	public native int svm_dll_export(double[] random, String savepath);
    static{
        // 加载动态库
        System.load("/home/linux/Templates/workspace/svm/libsvm.so");  
    }
	
	public static void main(String[] args) throws InterruptedException{
		double[] arr = new double[]{1.0,2.0,3.0,4.0,5.0,6.0,7.0,8.0,9.0,10.0};
		String savepath = "../model";
        // 调用库函数
		int ret = new SVM().svm_dll_export(arr, savepath);                   
		System.out.println("C++计算返回的结果是: "+ ret);
	}
}
  • 3
    点赞
  • 17
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
Utgard 是一个Java,用于连接 OPC DA 服务器,如果你想在Linux环境使用C++调用Utgard访问OPC DA服务器,你需要使用Java Native Interface(JNI)。 以下是一些步骤: 1.首先,在Linux系统上安装Java Development Kit(JDK)。 2.然后创建一个Java类来连接OPC DA服务器并实现所需的功能。 3.编译Java类并生成一个Java动态链接(.so文件)。 4.在C++代码中使用JNI调用Java动态链接。 下面是一个简单的示例: Java类: ```java import org.jinterop.dcom.common.JIException; import org.jinterop.dcom.core.JIVariant; import org.jinterop.dcom.core.JIString; import org.openscada.opc.lib.common.ConnectionInformation; import org.openscada.opc.lib.da.Item; import org.openscada.opc.lib.da.ItemState; import org.openscada.opc.lib.da.Server; import org.openscada.opc.lib.da.SyncAccess; public class OPCClient { public static void main(String[] args) throws Exception { // connect to an OPC DA server ConnectionInformation ci = new ConnectionInformation(); ci.setHost("localhost"); ci.setUser("user"); ci.setPassword("password"); ci.setClsid("B3AF0BF6-4C0C-4804-A122-6F3B160F4397"); Server server = new Server(ci, Executors.newSingleThreadScheduledExecutor()); // create an item and read its value Item item = server.getItemManager().getItem("Random.Int1"); SyncAccess syncAccess = new SyncAccess(server, 1000); syncAccess.addItem(item); syncAccess.bind(); ItemState itemState = item.read(syncAccess.getTransactionId()).get(); JIVariant jiVariant = itemState.getValue(); int value = jiVariant.getObjectAsInt(); System.out.println(value); // write a value to the item item.write(new JIVariant(new JIString("new value"))); // disconnect from the server server.dispose(); } } ``` 编译Java类并生成一个Java动态链接: ```bash javac -cp .:utgard.jar OPCClient.java javah -classpath .:utgard.jar -jni OPCClient gcc -shared -I $JAVA_HOME/include -I $JAVA_HOME/include/linux -o libOPCClient.so OPCClient.c -L. -lutgard ``` C++代码: ```c++ #include <jni.h> int main() { JavaVM *jvm; JNIEnv *env; JavaVMInitArgs vm_args; vm_args.version = JNI_VERSION_1_8; vm_args.nOptions = 0; vm_args.ignoreUnrecognized = JNI_FALSE; JNI_CreateJavaVM(&jvm, (void **)&env, &vm_args); jclass cls = env->FindClass("OPCClient"); jmethodID mid = env->GetStaticMethodID(cls, "main", "([Ljava/lang/String;)V"); jobjectArray args = env->NewObjectArray(0, env->FindClass("java/lang/String"), NULL); env->CallStaticVoidMethod(cls, mid, args); jvm->DestroyJavaVM(); } ``` 在编译C++代码时需要链接utgard和jni,如下所示: ```bash g++ -I $JAVA_HOME/include -I $JAVA_HOME/include/linux -L. -lutgard -ljvm -o main main.cpp ``` 注意:以上示例仅演示了如何使用JNI调用Java动态链接,具体的OPC DA连接实现需要根据自己的需求进行编写。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值