简介
- 开发环境
- 代码结构
- .h文件生成
- 编译生成so文件
- 运行
- 扩展(有包名的情况)
开发环境
- centos 6.8 ×64
[root@localhost jni]# cat /proc/version
Linux version 2.6.32-696.10.2.el6.x86_64 (mockbuild@c1bl.rdu2.centos.org) (gcc version 4.4.7 20120313 (Red Hat 4.4.7-18) (GCC) ) #1 SMP Tue Sep 12 14:33:29 UTC 2017
- jdk 1.8
目录/usr/local/java/jdk1.8.0_144
[root@localhost jni]# java -version
java version "1.8.0_144"
Java(TM) SE Runtime Environment (build 1.8.0_144-b01)
Java HotSpot(TM) 64-Bit Server VM (build 25.144-b01, mixed mode)
- g++ 4.4.7
[root@localhost jdk1.8.0_144]# g++ --version
g++ (GCC) 4.4.7 20120313 (Red Hat 4.4.7-18)
Copyright © 2010 Free Software Foundation, Inc.
本程序是自由软件;请参看源代码的版权声明。本软件没有任何担保;
包括没有适销性和某一专用目的下的适用性担保。
代码结构
为了方便大家能够快速入门,先写一个简单的示例来演示。
先看下代码结构:
- JavaMain.java java源代码
- CppLib.cpp C++源代码
- JavaMain.h 是由JavaMain.java生成的头文件
.h文件生成
public class JavaMain{
public static void main(String[] args){
System.out.println("Ok!");
new JavaMain().show();
}
public native void show();
static{
System.loadLibrary("cpp");
}
}
代码很简单,native来声明该方法非java方法。static代码块来加载动态库。
接下来就是生成.h文件。直接执行
javah JavaMain.java
生成JavaMain.h头文件
/* DO NOT EDIT THIS FILE - it is machine generated */
#include <jni.h>
/* Header for class JavaMain */
#ifndef _Included_JavaMain
#define _Included_JavaMain
#ifdef __cplusplus
extern "C" {
#endif
/*
* Class: JavaMain
* Method: show
* Signature: ()V
*/
JNIEXPORT void JNICALL Java_JavaMain_show
(JNIEnv *, jobject);
#ifdef __cplusplus
}
#endif
#endif
编译生成so文件
接下来就是引入头文件进行C/C++编码。
#include "JavaMain.h"
#include "jni.h"
JNIEXPORT void JNICALL Java_JavaMain_show
(JNIEnv * env, jobject jb){
printf("%s","cpp library\n");
}
内容很简单,就是打印一句话。
接下来就是编译,为了方便,我们使用make工具来执行编译过程。这里需要编写Makefile。对Makefile不熟的兄弟可以参考Makefile文件编写。对g++不熟的兄弟可以参考gcc编译参数
libcpp.so : CppLib.cpp
g++ -o $@ $+ -fPIC -shared -I/usr/local/java/jdk1.8.0_144/include -I/usr/local/java/jdk1.8.0_144/include/linux
.PHONY : clean
clean :
-rm libcpp.so
这里主要有几个参数需要注意
-
-fPIC -shared
代表编译成动态库 -
-I/usr/local/java/jdk1.8.0_144/include -I/usr/local/java/jdk1.8.0_144/include/linux
引入jni相关的头文件。我的jdk就安装在/usr/local/java/jdk1.8.0_144
下
接下来就是编译,直接执行make
命令,成功生成libcpp.so
文件。linux下库文件有个特点就是固定以lib开头,.so
为扩展名。
运行
得到so文件后,接下来就编译JavaMain.java。执行
javac JavaMain.java
得到JavaMain.class
执行:
java -Djava.library.path='.' JavaMain
java一般使用两个path:classpath 和 java.library.path
classpath是指向jar包的位置
java.library.path是非java类包的位置如(dll,so)
结果:
[root@localhost jni]# java -Djava.library.path='.' JavaMain
Ok!
cpp library
扩展(有包名的情况)
有不少兄弟在正常的项目开发中,javah和java命令会出现各种错误,比如"找不到**类"。这里我就做一个完整的示例。
有以下几点需要注意:
- 执行javah和java命令要在源码目录下,也就是src/java目录下。
- 执行java命令来运行时候,需要制定java.library.path的路径。
/**
* 在java目录下
*
* 生成头文件
* javah com.eric.demo.JavaMain
*
* 编译
* javac com.eric.demo.JavaMain.java
*
* 运行
* java com.eric.demo.JavaMain -Djava.library.path=/code/jni2/src/main/jni
*/