Jni教程(一)—Linux下jni调用简介

2018-08-23 13:31:57 浏览数 (1)

简介

  • 开发环境
  • 代码结构
  • .h文件生成
  • 编译生成so文件
  • 运行
  • 扩展(有包名的情况)

开发环境

  • centos 6.8 ×64
代码语言:javascript复制
[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
代码语言:javascript复制
[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
代码语言:javascript复制
[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.
本程序是自由软件;请参看源代码的版权声明。本软件没有任何担保;
包括没有适销性和某一专用目的下的适用性担保。

代码结构

为了方便大家能够快速入门,先写一个简单的示例来演示。

先看下代码结构:

1.png

  • JavaMain.java java源代码
  • CppLib.cpp C 源代码
  • JavaMain.h 是由JavaMain.java生成的头文件

.h文件生成

代码语言:javascript复制
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文件。直接执行

代码语言:javascript复制
javah JavaMain.java

生成JavaMain.h头文件

代码语言:javascript复制
/* 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 编码。

代码语言:javascript复制
#include "JavaMain.h"
#include "jni.h"
JNIEXPORT void JNICALL Java_JavaMain_show
  (JNIEnv * env, jobject jb){
      printf("%s","cpp libraryn");
}

内容很简单,就是打印一句话。

接下来就是编译,为了方便,我们使用make工具来执行编译过程。这里需要编写Makefile。对Makefile不熟的兄弟可以参考Makefile文件编写。对g 不熟的兄弟可以参考gcc编译参数

代码语言:javascript复制
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。执行

代码语言:javascript复制
javac JavaMain.java

得到JavaMain.class

执行:

代码语言:javascript复制
java -Djava.library.path='.' JavaMain

java一般使用两个path:classpath 和 java.library.path classpath是指向jar包的位置 java.library.path是非java类包的位置如(dll,so)

结果:

代码语言:javascript复制
[root@localhost jni]# java -Djava.library.path='.' JavaMain
Ok!
cpp library

扩展(有包名的情况)

有不少兄弟在正常的项目开发中,javah和java命令会出现各种错误,比如"找不到**类"。这里我就做一个完整的示例。

2.png

有以下几点需要注意:

  • 执行javah和java命令要在源码目录下,也就是src/java目录下。
  • 执行java命令来运行时候,需要制定java.library.path的路径。
代码语言:javascript复制
/**
* 在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
*/

0 人点赞