参考: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函数,需要给他传参数的情况。