龙空技术网

java与C集成的方法(JNI),并使用maven进行打包

alexIT技术 252

前言:

此时同学们对“javayyyymmddhh”大致比较讲究,兄弟们都需要分析一些“javayyyymmddhh”的相关知识。那么小编同时在网摘上汇集了一些有关“javayyyymmddhh””的相关文章,希望兄弟们能喜欢,各位老铁们快快来学习一下吧!

现如今的应用中,有很多算法是用C语言进行开发的,利用C语言进行进行科学计算,矩阵运算等,效率会比较高,外层应用如果使用java,就需要有一个桥梁来链接java与C,这种技术就是JNI。JNI是Java Native Interface的缩写,它提供了若干的API实现了Java和其他语言的通信(主要是C&C++)。从Java1.1开始,JNI标准成为java平台的一部分,它允许Java代码和其他语言写的代码进行交互。

现如今我们已经习惯了使用maven来对项目进行打包管理,那么如果加入了C语言这一层,该如何进行集成和打包呢?本文就使用了一个简单的例子来展示如何使用JNI来进行java与C的集成以及如何进行打包管理。

假设现在的算法是求a除以b的结果,由于我们在实际的接口定义中,经常定义复杂的结构体来,为了展示常用的参数传递方法,我定义了结构体来表示入参和出参。

相关的接口定义如下:

a)algorithm.h头文件中定义入参ParamIn,出参ParamOut,接口函数ParamOut divide(ParamIn in);

#ifndef ALGORITHM_ALGORITHM_H#define ALGORITHM_ALGORITHM_H#pragma pack(1)typedef struct { double a; double b;}ParamIn;typedef struct { double result;}ParamOut;/** * 除法运算 * @param in * @return */void divide(ParamIn* in,ParamOut *out);#pragma pack()#endif //ALGORITHM_ALGORITHM_H

b)algorithmCalc.cpp函数实现为

#include "algorithm.h"#include <stdio.h>#include <string.h>void divide(ParamIn* in,ParamOut *out){ double result = in->a/in->b; ParamOut paramOut; memset(&paramOut,0x00, sizeof(ParamOut)); out->result = result; printf("the result is %3.8f",out->result);}

c)使用main函数来进行单元测试

#include <iostream>#include "src/algorithm.h"int main() { std::cout << "Hello, World!" << std::endl; double a = 10; double b = 13; ParamIn paramIn; memset(&paramIn,0x00, sizeof(ParamIn)); paramIn.a = a; paramIn.b = b; ParamOut out; memset(&out,0x00, sizeof(ParamOut)); divide(&paramIn,&out); return 0;}

d)为了使用maven来进行打包管理,在你的c工程当中新增pom.xml来将应用打包为nar包。注意<packaging>nar</packaging>需要设置为nar,才会打包为nar包。

<?xml version="1.0" encoding="UTF-8"?><project xmlns="" xmlns:xsi="" xsi:schemaLocation=" "> <modelVersion>4.0.0</modelVersion> <groupId>com.alex.algorithm</groupId> <artifactId>alg</artifactId> <version>1.0.0-SNAPSHOT</version> <packaging>nar</packaging> <dependencies> <!-- native loader --> <dependency> <groupId>org.scijava</groupId> <artifactId>native-lib-loader</artifactId> <version>2.1.3</version> </dependency> </dependencies> <properties> <maven.build.timestamp.format>yyyyMMddHHmm</maven.build.timestamp.format> </properties> <build> <pluginManagement> <plugins> <plugin> <groupId>com.github.maven-nar</groupId> <artifactId>nar-maven-plugin</artifactId> <version>3.4.0</version> <extensions>true</extensions> <configuration> <cpp> <options> <option>-fPIC</option> <option>-I${project.basedir}</option> <option>-g</option> <option>-ggdb</option> </options> </cpp> </configuration> </plugin> <plugin> <groupId>org.codehaus.mojo</groupId> <artifactId>versions-maven-plugin</artifactId> <version>2.2</version> <configuration> <generateBackupPoms>false</generateBackupPoms> </configuration> </plugin> <plugin> <artifactId>maven-compiler-plugin</artifactId> <version>3.3</version> </plugin> <plugin> <artifactId>maven-source-plugin</artifactId> <version>2.4</version> </plugin> </plugins> </pluginManagement> <resources> <resource> <directory>${project.basedir}</directory> <includes> <include>src/*.h</include> </includes> <targetPath>${project.build.directory}/nar/${project.artifactId}-${project.version}-noarch/include</targetPath> </resource> </resources> <plugins> <plugin> <groupId>org.codehaus.mojo</groupId> <artifactId>versions-maven-plugin</artifactId> </plugin> <plugin> <groupId>com.github.maven-nar</groupId> <artifactId>nar-maven-plugin</artifactId> <extensions>true</extensions> <configuration> <cpp> <sourceDirectory>${project.basedir}</sourceDirectory> <includes> <include>src/*.cpp</include> </includes> <multiThreaded>true</multiThreaded> </cpp> <libraries> <library> <type>static</type> </library> </libraries> </configuration> </plugin> <plugin> <artifactId>maven-source-plugin</artifactId> <executions> <execution> <id>attach-sources</id> <goals> <goal>jar</goal> </goals> </execution> </executions> </plugin> </plugins> </build></project>

e)进入项目下,执行打包命令mvn clean package就可以在项目下的target目录当中生成nar包了,由于我的电脑是MAC的,所以生成的nar包是alg-1.0.0-SNAPSHOT-x86_64-MacOSX-gpp-static.nar,如果是linux,生成的nar包就是alg-1.0.0-SNAPSHOT-amd64-Linux-gpp-jni.nar

下面是需要在java层与C进行集成,定义一个jni层的java应用名字就是jni

a)定义与C结构体对应的ParamIn,ParamOut,以及对应的Native函数

package com.alex;import javolution.io.Struct;public class ParamIn extends Struct { public final Float64 a = new Float64(); public final Float64 b = new Float64();}package com.alex;import javolution.io.Struct;public class ParamOut extends Struct { public final Float64 result = new Float64();}package com.alex;public class Native { static { try { NarSystem.loadLibrary(); }catch (Throwable e){ } }}package com.alex;public class Divide extends Native{ public static native void divide(long in,long out);}

b)执行mvn clean package生成对应的class,在target/class下面执行javah -classpath . com.alex.Divide,会生成对应的.h文件com_alex_Divide.h

c)在src/main下面新增c++的文件夹,新增divide.cpp函数,函数内部如下:

#include <jni.h>#include <stdio.h>#include "com_alex_Divide.h"#include "src/algorithm.h"#ifndef _Included_com_alex_Divide#define _Included_com_alex_Divide#ifdef __cplusplusextern "C" {#endif/* * Class: com_alex_Divide * Method: divide * Signature: (JJ)V */JNIEXPORT void JNICALL Java_com_alex_Divide_divide (JNIEnv *env, jclass clazz, jlong in, jlong out){ ParamIn* a = (ParamIn*)in; ParamOut* b = (ParamIn*)out; //此处为src/algorithm.h中的函数 divide(a,b); }#ifdef __cplusplus}#endif#endif

最后新增新的工程,引入该jni层的nar包即可实现对C程序的调用

public class TestDivide {

public static void main(String[] args) {

int a = 11;

int b = 12;

ParamIn paramIn = new ParamIn();

paramIn.a.set(a);

paramIn.b.set(b);

ParamOut out = new ParamOut();

Divide.divide(paramIn.address(),out.address());

System.out.println(out.result);

}

}

对应的pom如下

<?xml version="1.0" encoding="UTF-8"?><project xmlns="" xmlns:xsi="" xsi:schemaLocation=" "> <modelVersion>4.0.0</modelVersion> <groupId>com.alex</groupId> <artifactId>testjni</artifactId> <version>1.0.0-SNAPSHOT</version> <dependencies> <dependency> <groupId>org.scijava</groupId> <artifactId>native-lib-loader</artifactId> <version>2.1.3</version> </dependency> <dependency> <groupId>org.javolution</groupId> <artifactId>javolution-core-java</artifactId> <version>6.0.0</version> </dependency> <dependency> <groupId>com.alex</groupId> <artifactId>jni</artifactId> <version>1.0.0-SNAPSHOT</version> <classifier>epoch</classifier> <type>jar</type> </dependency> <dependency> <groupId>com.alex</groupId> <artifactId>jni</artifactId> <version>1.0.0-SNAPSHOT</version> <type>nar</type> </dependency> <dependency> <groupId>com.alex</groupId> <artifactId>jni</artifactId> <version>1.0.0-SNAPSHOT</version> <classifier>x86_64-MacOSX-gpp-jni</classifier> <type>nar</type> </dependency> </dependencies></project>

这样一个jni工程就结束了

jni应用的github地址为git@github.com:kangyz/jni.git

调用jni的应用为git@github.com:kangyz/testjni.git

jni调用的c应用为git@github.com:kangyz/algorithm.git

标签: #javayyyymmddhh #ios调用java #java执行maven命令 #java与c通信 #java调用cpp