欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页  >  IT编程

windows和linux环境下java调用C++代码-JNI技术

程序员文章站 2022-05-04 12:21:55
最近部门做安卓移动开发的需要调C++的代码,困难重重,最后任务交给了我,查找相关资料,没有一个教程能把不同环境(windows,linux)下怎么调用说明白的,自己在实现的过程中踩了几个坑,在这里总结下,希望看到的以后能少走弯路。

最近部门做安卓移动开发的需要调c++的代码,困难重重,最后任务交给了我,查找相关资料,没有一个教程能把不同环境(windows,linux)下怎么调用说明白的,自己在实现的过程中踩了几个坑,在这里总结下,希望看到的以后能少走弯路。

使用工具:

1.java使用的ide为eclipse
2.windows环境下c++使用的ide为visual studio 2010
3.linux环境下c++使用的编译器为gcc/g++

一.windows环境下java调用c++代码

1.1新建java工程,生成相应头文件

eclipse新建工程名为"jnidemo"的java工程,在包名为com.woniu.native下新建"nativecpp.java"类,如下:

package com.woniu.native;
 
public class nativecpp {
    public native void fun1();
    public native int  fun2(int a, int b);
    public native void fun3(string url1, string url2);
}

windows和linux环境下java调用C++代码-JNI技术

编译生成.class文件

进入工程下的target\classes目录下,执行"javah -jni com.woniu.native.nativecpp",运行结果如下:

windows和linux环境下java调用C++代码-JNI技术

此时,会在classes目录下生成"com_woniu_native_nativecpp.h"头文件,头文件内容如下:

/* do not edit this file - it is machine generated */
#include <jni.h>
/* header for class com_woniu_native_nativecpp */
 
#ifndef _included_com_woniu_native_nativecpp
#define _included_com_woniu_native_nativecpp
#ifdef __cplusplus
extern "c" {
#endif
/*
 * class:     com_woniu_native_nativecpp
 * method:    fun1
 * signature: ()v
 */
jniexport void jnicall java_com_woniu_native_nativecpp_fun1
  (jnienv *, jobject);
 
/*
 * class:     com_woniu_native_nativecpp
 * method:    fun2
 * signature: (ii)i
 */
jniexport jint jnicall java_com_woniu_native_nativecpp_fun2
  (jnienv *, jobject, jint, jint);
 
/*
 * class:     com_woniu_native_nativecpp
 * method:    fun3
 * signature: (ljava/lang/string;ljava/lang/string;)v
 */
jniexport void jnicall java_com_woniu_native_nativecpp_fun3
  (jnienv *, jobject, jstring, jstring);
 
#ifdef __cplusplus
}
#endif
#endif

1.2 c++生成动态库
vs2010新建工程名为"jnidll"的win32控制台应用程序,win32应用程序向导界面选择 "dll"
windows和linux环境下java调用C++代码-JNI技术

创建完成后,把2.1中生成的"com_woniu_native_nativecpp.h"头文件放入该工程,并把头文件中的#include <jni.h>改为 "jni.h",
把jdk下include文件夹下的"jni.h"和include下win32文件夹下的"jni_md.h"头文件也一同放入创建的工程中。

工程目录如下:
windows和linux环境下java调用C++代码-JNI技术

编辑jnidll.cpp源码文件,实现头文件中的函数,如下:

/********************************************************
copyright (c), 2016-2017,
filename:   jni
author:     woniu201
email:      wangpengfei.201@163.com
created:    2017/09/20
description:jni function
********************************************************/
#include "stdafx.h"
#include "com_woniu_native_nativecpp.h"
#include "stdio.h"
#include "stdlib.h"
 
jniexport void jnicall java_com_woniu_native_nativecpp_fun1
    (jnienv *, jobject)
{
    printf("hello world\n");
}
 
jniexport jint jnicall java_com_woniu_native_nativecpp_fun2
    (jnienv *, jobject, jint a, jint b)
{
    return a + b;
}
 
char* jstringtochar(jnienv* env, jstring jstr) {
    char* rtn = null;
    jclass clsstring = env->findclass("java/lang/string");
    jstring strencode = env->newstringutf("gb2312");
    jmethodid mid = env->getmethodid(clsstring, "getbytes", "(ljava/lang/string;)[b");
    jbytearray barr = (jbytearray) env->callobjectmethod(jstr, mid, strencode);
    jsize alen = env->getarraylength(barr);
    jbyte* ba = env->getbytearrayelements(barr, jni_false);
    if (alen > 0) {
        rtn = (char*) malloc(alen + 1);
        memcpy(rtn, ba, alen);
        rtn[alen] = 0;
    }
    env->releasebytearrayelements(barr, ba, 0);
    return rtn;
}
 
jniexport void jnicall java_com_woniu_native_nativecpp_fun3
    (jnienv *env, jobject, jstring url1, jstring url2)
{
    //jstringתchar*
    char* purl1 = jstringtochar(env, url1);
    char* purl2 = jstringtochar(env, url2);
    printf("url1 = %s\n", purl1);
    printf("url2 = %s\n", purl2);
}

我本机是64位系统,使用的是64位jdk,这里生成的动态库也要生成64位的库,否则调用的时候报如下错误:

windows和linux环境下java调用C++代码-JNI技术

更改vs编译生成64位dll,步骤如下:

windows和linux环境下java调用C++代码-JNI技术

windows和linux环境下java调用C++代码-JNI技术

windows和linux环境下java调用C++代码-JNI技术

编译生成解决方案,这时候会在工程根目录下,生成"x64文件夹",debug文件夹下会有动态库"jnidll.dll"

windows和linux环境下java调用C++代码-JNI技术

1.3 java调用dll

package com.woniu.jnidemo;
 
import com.woniu.native.nativecpp;
 
public class app 
{
    public static void main( string[] args )
    {
        system.load("d:\\vs2010\\vc\\jnidll\\x64\\debug\\jnidll.dll");
        nativecpp nativecpp = new nativecpp();
        nativecpp.fun1();
        system.out.println(nativecpp.fun2(3, 3));
        nativecpp.fun3("www.baidu.com", "www.haoservice.cn");
    }
}

运行结果如下:

windows和linux环境下java调用C++代码-JNI技术

二:linux(centos)环境下java调用c++代码

2.1 编译环境

a.安装gcc和g++

yum install gcc-c++


b.安装jdk
去官网上下载jdk安装包,建议使用rpm安装包,会自动配置环境变量。安装完后如下:

windows和linux环境下java调用C++代码-JNI技术

本机的安装目录为:/usr/java/jdk1.8.0_144/,不同版本可能不同。

这里一定要注意不能安装openjdk,因为openjdk没有include目录,编译时需要用到include目录的头文件。

2.2 制作动态库(so库)

a.创建文件夹"jniso",mkdir jniso。


b.把2.1中生成的头文件"com_woniu_native_nativecpp.h"拷贝过来,#include "jni.h"改为#include <jni.h>


c.新建jni.cpp源文件,添加如下代码:
#include <jni.h>
#include "com_woniu_native_nativecpp.h"
#include "stdio.h"
#include "stdlib.h"
#include "string.h"
 
jniexport void jnicall java_com_woniu_native_nativecpp_fun1 (jnienv *, jobject)
{
        printf("hello world\n");
}
 
jniexport jint jnicall java_com_woniu_native_nativecpp_fun2
        (jnienv *, jobject, jint a, jint b)
{
        return a + b;
}
 
char* jstringtochar(jnienv* env, jstring jstr) {
        char* rtn = null;
        jclass clsstring = env->findclass("java/lang/string");
        jstring strencode = env->newstringutf("gb2312");
        jmethodid mid = env->getmethodid(clsstring, "getbytes", "(ljava/lang/string;)[b");
        jbytearray barr = (jbytearray) env->callobjectmethod(jstr, mid, strencode);
        jsize alen = env->getarraylength(barr);
        jbyte* ba = env->getbytearrayelements(barr, jni_false);
        if (alen > 0) {
                rtn = (char*) malloc(alen + 1);
                memcpy(rtn, ba, alen);
                rtn[alen] = 0;
        }
        env->releasebytearrayelements(barr, ba, 0);
        return rtn;
}
 
jniexport void jnicall java_com_woniu_native_nativecpp_fun3
        (jnienv *env, jobject, jstring url1, jstring url2)
{
        char* purl1 = jstringtochar(env, url1);
        char* purl2 = jstringtochar(env, url2);
        printf("url1 = %s\n", purl1);
        printf("url2 = %s\n", purl2);
}

d.编译,生成动态库
g++ -fpic -c jni.cpp -i /usr/java/jdk1.8.0_144/include/ -i /usr/java/jdk1.8.0_144/include/linux/
g++ -shared jni.o -o jni.so

2.3 java调用jni.so

import com.woniu.native.nativecpp;
 
public class app 
{
    public static void main( string[] args )
    {
        //windows环境下加载库
        //system.load("d:\\vs2010\\vc\\jnidll\\x64\\debug\\jnidll.dll");
        
        //linux下加载库
        system.load("/mnt/hgfs/svn/svn/demo/jniso/jni.so");
        
        nativecpp nativecpp = new nativecpp();
        nativecpp.fun1();
        system.out.println(nativecpp.fun2(3, 3));
        nativecpp.fun3("www.baidu.com", "www.haoservice.cn");
    }
}

运行结果如下:

windows和linux环境下java调用C++代码-JNI技术

关注下面公众号,回复"105"获取windows下生成dll源码

关注下面公众号,回复"106"获取linux下生成so源码

windows和linux环境下java调用C++代码-JNI技术