您的位置 首页 java

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

现如今的应用中,有很多算法是用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=" org /POM/4.0.0 ">
 <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>
 < plugin Management>
 <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 __cplusplus
extern "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应用的 git hub地址为git@github.com:kangyz/jni.git

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

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

文章来源:智云一二三科技

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

文章地址:https://www.zhihuclub.com/176909.shtml

关于作者: 智云科技

热门文章

网站地图