JNI编程Demo----Java程序调用C&C++编译好的库文件
2017-07-21 17:03
531 查看
JNI是Java Native Interface的缩写,它提供了若干的API实现了Java和其他语言的通信(主要是C&C++)。下面用一个Demo实现通过JNI,Java如何调用C&C++的库文件(Windows下是dll文件,Linux下是so文件)。
本文在Windows下实现,因此调用的是dll文件,期间也会说明linux下调用so文件有什么不同之处,环境如下:
- 操作系统:Win10 Pro
- JDK:1.7(1.8也完全ok)
- IDE:Jetbrains IDEA 2016.3 Community
一、安装GCC环境
Windows下,一般选择安装MinGW,下载地址:下载地址,安装好后,将MinGW安装目录下的bin目录加入PATH中,然后打开命令行,输入gcc -v,出现如下信息即证明安装完成:
二、JNI Demo
首先用IDEA创建一个Java工程,在src目录下创建一个包,包名为cn.hust.demo,如图:
在该包下编写类TestAdd,我们要实现的功能是两个数相加:
方法System.loadLibrary()用来加载dll(windows)或so(Linux)库,只需名称即可,无需加入文件名后缀(.dll或.so)。native关键字将函数add(int a, int b)声明为本地函数,由C/C++实现。具体的实现就在Add.dll(Windows平台)或libAdd.so(Linux平台)中。注意,在Linux平台下,so文件前面要有“lib”前缀(但是System.loadLibrary()的参数仍然和Windows下一样,不用带“lib”),否则会找不到库文件。
生成头文件
首先将TestAdd.java编译一下,出现TestAdd.class:
然后配置生成头文件的命令:
File–>Settings–>Tools–>External Tools,点击右边的“+”号,如下填写:
Name为“Generate Header File”,上图中Tool Settings部分的填写:
Program:
Parameters:
Working Dictionary:
如此配置好后,在TestAdd.java文件上右键,选择External tools–>Generate Header File:
即生成了头文件如下:
代码如下:
在此代码中,函数命名为Java_<包>_<类名>_<函数名>,参数中除前两个参数外,后面两个是add函数的参数类型,jint对应int型。
编写C语言文件
在jni目录下编写add.c文件:
代码:
编译C语言文件,生成dll库
仍然同生成头文件一样,用IDEA的external tools一键生成dll文件。因此打开external tool配置界面,点击“+”号,创建一个名为“Generate DLL”(如果是Linux环境下,你就命名为“Generate SO”)的tool:
具体配置如下:
Program:
Parameters:
Working dictionary:
配置好后,在工作目录下新建lib文件夹,然后右键Add.c,选择external tools中的“Generate DLL”,在lib目录下生成DLL文件:
运行Java程序,得出结果
此时,运行一开始的java程序会报错找不到库文件:
这时,需要在运行参数中配置如下:
将VM options中加入:
即library path指向DLL文件所在目录即可。
此时再运行java程序,即得出正确结果:
三、附注
本文展示了生成头文件、写C语言程序和生成库文件的全过程Demo,一般情况下,是直接拿到库文件进行调用的,因此前面的过程可以略去,只需知道该库文件哪些函数可以调用,直接用Java进行调用即可。
本文在Windows下实现,因此调用的是dll文件,期间也会说明linux下调用so文件有什么不同之处,环境如下:
- 操作系统:Win10 Pro
- JDK:1.7(1.8也完全ok)
- IDE:Jetbrains IDEA 2016.3 Community
一、安装GCC环境
Windows下,一般选择安装MinGW,下载地址:下载地址,安装好后,将MinGW安装目录下的bin目录加入PATH中,然后打开命令行,输入gcc -v,出现如下信息即证明安装完成:
二、JNI Demo
首先用IDEA创建一个Java工程,在src目录下创建一个包,包名为cn.hust.demo,如图:
在该包下编写类TestAdd,我们要实现的功能是两个数相加:
package cn.hust.demo; // Created by LCJ on 2017.7.21. public class TestAdd { static { System.loadLibrary("Add"); } private native int add(int a, int b); public static void main(String[] args) { int c = new TestAdd().add(3, 4); System.out.println("Result is: " + c); } }
方法System.loadLibrary()用来加载dll(windows)或so(Linux)库,只需名称即可,无需加入文件名后缀(.dll或.so)。native关键字将函数add(int a, int b)声明为本地函数,由C/C++实现。具体的实现就在Add.dll(Windows平台)或libAdd.so(Linux平台)中。注意,在Linux平台下,so文件前面要有“lib”前缀(但是System.loadLibrary()的参数仍然和Windows下一样,不用带“lib”),否则会找不到库文件。
生成头文件
首先将TestAdd.java编译一下,出现TestAdd.class:
然后配置生成头文件的命令:
File–>Settings–>Tools–>External Tools,点击右边的“+”号,如下填写:
Name为“Generate Header File”,上图中Tool Settings部分的填写:
Program:
$JDKPath$/bin/javah;
Parameters:
-jni -classpath $OutputPath$ -d ./jni $FileClass$
Working Dictionary:
$ProjectFileDir$
如此配置好后,在TestAdd.java文件上右键,选择External tools–>Generate Header File:
即生成了头文件如下:
代码如下:
/* DO NOT EDIT THIS FILE - it is machine generated */ #include <jni.h> /* Header for class cn_hust_demo_TestAdd */ #ifndef _Included_cn_hust_demo_TestAdd #define _Included_cn_hust_demo_TestAdd #ifdef __cplusplus extern "C" { #endif /* * Class: cn_hust_demo_TestAdd * Method: add * Signature: (II)I */ JNIEXPORT jint JNICALL Java_cn_hust_demo_TestAdd_add (JNIEnv *, jobject, jint, jint); #ifdef __cplusplus } #endif #endif
在此代码中,函数命名为Java_<包>_<类名>_<函数名>,参数中除前两个参数外,后面两个是add函数的参数类型,jint对应int型。
编写C语言文件
在jni目录下编写add.c文件:
代码:
#include <jni.h> #include <stdio.h> #include "cn_hust_demo_TestAdd.h" JNIEXPORT jint JNICALL Java_cn_hust_demo_TestAdd_add(JNIEnv *env, jobject o, jint a, jint b) { jint c = a + b; printf("The sum of %d + %d is: %d", a, b, c); return c; }
编译C语言文件,生成dll库
仍然同生成头文件一样,用IDEA的external tools一键生成dll文件。因此打开external tool配置界面,点击“+”号,创建一个名为“Generate DLL”(如果是Linux环境下,你就命名为“Generate SO”)的tool:
具体配置如下:
Program:
D:\Program Files\MinGW\mingw64\bin\gcc.exe即你的gcc目录,Linux下也同样是gcc路径
Parameters:
-Wl,--add-stdcall-alias -I"$JDKPath$\include" -I"$JDKPath$\include\win32" -shared -o ./lib/$FileNameWithoutExtension$.dll ./jni/$FileNameWithoutExtension$.c注意,如果是Linux环境下,win32要改成linux,dll文件的文件名也要改,前面要加上lib前缀,同时是so文件而非dll文件,命令细节也要更改,最终如此:
-I"$JDKPath$\include" -I"$JDKPath$\include\linux" -fPIC -shared -o ./lib/lib$FileNameWithoutExtension$.so ./jni/$FileNameWithoutExtension$.c
Working dictionary:
$ProjectFileDir$
配置好后,在工作目录下新建lib文件夹,然后右键Add.c,选择external tools中的“Generate DLL”,在lib目录下生成DLL文件:
运行Java程序,得出结果
此时,运行一开始的java程序会报错找不到库文件:
这时,需要在运行参数中配置如下:
将VM options中加入:
-Djava.library.path=I:\IDEAWorkspace\JNI\TestJNIDemo\lib
即library path指向DLL文件所在目录即可。
此时再运行java程序,即得出正确结果:
三、附注
本文展示了生成头文件、写C语言程序和生成库文件的全过程Demo,一般情况下,是直接拿到库文件进行调用的,因此前面的过程可以略去,只需知道该库文件哪些函数可以调用,直接用Java进行调用即可。
相关文章推荐
- init.rc文件里面启动c++程序,通过jni调用java实现
- 用JNI进行Java编程---从C/C++程序调用Java代码
- 用JNI进行Java编程---从Java程序调用C/C++代码
- android studio中使用ndk编译.so文件,调用C/C++代码(jni编程)
- JNI编程 —— 让C++和Java相互调用
- 使用JNI进行混合编程:在Java中调用C/C++本地库
- windows下java JNI编程技巧——JAVA调用c/c++(4)
- c/c++ native 层 通过 JNI API 调用 java 层 的AudioTrack 来播放 音频文件
- 使用JNI进行混合编程:在C/C++中调用Java代码
- Chap5:使用JNI技术实现java程序调用第三方dll(c/c++)文件的功能
- linux下使用jni实现c++调用java程序(2)找不到java类的问题
- 如果 C++程序要调用已经被编译后的C 函数,该怎么办?extern "C"
- java程序调用C、C++动态库的几种实现方式,即JNI的应用方式
- 使用JNI进行混合编程:在C/C++中调用Java代码
- JNI编程 —— 让C++和Java相互调用
- 3Java程序JNI调用C++之修改属性调用方法
- JNI编程 —— 让C++和Java相互调用
- 【MATLAB与C的混合编程】之【C程序调用M文件编译后得到的DLL文件】
- JNI编程—— 让C++和Java相互调用
- 2Java程序JNI调用C++之四步骤