ubuntu14.04下通过JNI使用C++跨语言调用java

参考:https://blog.csdn.net/wangyuchun_799/article/details/46978133

https://www.cnblogs.com/wanghaiyang1930/p/6604319.html

https://www.cnblogs.com/andyliu1988/p/6041542.html

软件环境及工具

  • ubuntu14.04
  • eclipse-jee-2018-09-linux-gtk-x86_64.tar.gz
  • CLion-2017.2.2.tar.gz

一、java环境配置

官网下载jdk,安装完后,配置环境变量。用下面方法检查是否安装成功。

hl@hl-Lenovo-Y520-15IKBN:~$ java -version
java version "9"
Java(TM) SE Runtime Environment (build 9+181)
Java HotSpot(TM) 64-Bit Server VM (build 9+181, mixed mode)

二、在eclipse中创建java工程

新建java project,命名为Demo,这里不创建package,直接新建一个Demo.java文件。

public class Demo {
	private static int magic_counter = 777;
	 
	     public static void callback() {
	     System.out.println("Hello world in java from cplusplus");
	     System.out.print("Magic number: ");
	     System.out.println(magic_counter);
	    }
}

在终端使用如下命令编译,生成Demo.class文件。此文件在Demo/bin下出现。

hl@hl-Lenovo-Y520-15IKBN:~/eclipse-workspace/Demo/src$ javac Demo.java 

生成头文件,根据*.java类生成对应的JNI头文件*.h,需要使用Java的javah命令,检查javah命令是否存在。

hl@hl-Lenovo-Y520-15IKBN:~$ which javah
/usr/local/java/jdk-9/bin/javah

进入终端,进入你工程的bin文件夹,使用javah命令生成头文件。

hl@hl-Lenovo-Y520-15IKBN:~/eclipse-workspace/Demo/bin$ javah Demo

或者配置eclipse的编译环境,可以在eclipse中调用javah命令生成头文件。

点击如下图中eclipse按钮:

     ,注意点击该图标右侧的三角形,在弹出菜单中,选择“External Tools Configuration...”,弹出一个页面,双击左栏的“Program”一项,会创建一个子项目,并按如下图中填写的信息参考填写:

      第一项:Name。即编译程序名字,我们配置的就是运行javah命令,所以直接命名为javah。

      第二项:Location。即javah文件所在的目录,可以通过“which javah”命令查看。

      第三项:Working Directory。即编译*.java文件所生成的.class文件存放在哪一个目录,${project_loc}表示编译的java文件所属的工程位置。

      第四项:Argument。运行编译命令时附加的参数,目的是在当前工程下的jni目录下生成与java文件同名的.h头文件。

      配置好后,点击“Apply”按钮保存设置,就可以选择java文件,并点击运行按钮运行了,如下图,注意是刚刚我们配置好的那个按钮,如果你把鼠标放在该按钮上(注意不是三角形)就会提示你“Run javah”,点击这个按钮。(注意这里一定要选中当前需要运行的Demo.java文件,再点击那个“Run javah”按钮,不然会报错)。

这时你可以看见Demo工程下生成了一个jni文件夹,里面有一个Demo.h文件。


查看类中成员的签名,(这里,如果你的类写的复杂点,里面成员函数比较多,在生成的.h文件中也能看到每个成员的签名。)

hl@hl-Lenovo-Y520-15IKBN:~/eclipse-workspace/Demo/src$ javap -s -p Demo.class
Compiled from "Demo.java"
public class Demo {
  private static int magic_counter;
    descriptor: I
  public Demo();
    descriptor: ()V

  public static void callback();
    descriptor: ()V

  static {};
    descriptor: ()V
}

到这里之后,我看有的博客写了一个Demo.c文件,然后gcc编译产生.so文件,通过动态链接库的方式调用。gcc使用的命令:

gcc -fPIC -I <jni.h文件路径> -I <jni_md.h文件路径> -shared -o libDemo.so Demo.c

到这里我有点不明白我要干嘛了。。。。。感觉跟我想象中的不太一样。。。。

好了。。以上是踩坑。。。。下面重新开始。

===========================================分界线==========================================

三、在clion中创建c++工程

接着前面的Demo工程,在产生Demo.class文件之后,就可以开始创建c++代码了。新建demo工程,新建main.cpp,下面的"-Djava.class.path=/home/hl/eclipse-workspace/Demo/bin",要改成你自己的Demo.class所在路径。(坑啊。。。)

//main.cpp
#include <jni.h>
#include <string>
#include <iostream>
#include <memory.h>
using namespace std;

int main()
{
    char opt1[] = "-Djava.compiler=NONE"; /** 暂时不知道啥意思,网上抄来的 */
    char opt2[] = "-Djava.class.path=/home/hl/eclipse-workspace/Demo/bin";  /** 指定Java类编译后.class文件所在的目录 */
    char opt3[] = "-verbose:NONE";        /** 暂时不知道啥意思,网上抄来的 */

    JavaVMOption options[3];
    options[0].optionString = opt1; options[0].extraInfo = NULL;
    options[1].optionString = opt2; options[1].extraInfo = NULL;
    options[2].optionString = opt3; options[2].extraInfo = NULL;

    JavaVMInitArgs jargv;
    jargv.version = JNI_VERSION_1_6; /** JDK JNI VERSION*/
    jargv.nOptions = 3;
    jargv.options = options;
    jargv.ignoreUnrecognized = JNI_TRUE;

    JavaVM* jvm = NULL;
    JNIEnv* jenv = NULL;
    jint res = JNI_CreateJavaVM( &jvm, (void**)&jenv, &jargv );//创建虚拟机
    if ( res < 0 )
        return -1;

    jclass jc = jenv->FindClass( "Demo" );
    if ( NULL == jc  ) {
        if( jenv->ExceptionOccurred()  )
            jenv->ExceptionDescribe();
        else {
            std::cout << "jc null" << std::endl;
        }
        return 1;
    }

    jmethodID jmid = jenv->GetStaticMethodID( jc, "callback", "()V" );
    if ( NULL == jmid )
        return -3;

    jenv->CallStaticVoidMethod( jc, jmid );


    /** 在网上没有找到任何关于空间相关 JavaVM 和 JNIEnv 资源释放的描述 */
    jvm->DestroyJavaVM();
    std::cout << "Hello, World!" << std::endl;
    return 0;
}

编写CMakelists.txt文件,include_directories里面是jni.h ,jni_md.h所在的路径。link_directories里面是JVM虚拟机(libjvm.so文件)所在路径。

cmake_minimum_required(VERSION 3.8)
project(demo)

set(CMAKE_CXX_STANDARD 11)
include_directories("/usr/local/java/jdk-9/include" "/usr/local/java/jdk-9/include/linux")
link_directories(/usr/local/java/jdk-9/lib/server )
set(SOURCE_FILES main.cpp)
add_executable(demo ${SOURCE_FILES})

target_link_libraries(
        demo
        jvm
)

build,run之后结果:

 大功告成!!!!心累。

接下来我想尝试一下调用java函数,需要给他传参数的情况。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值