java 通過jni調用linux so動态庫
準備
開發
java
C++
總結
歡迎轉載 位址:
https://blog.csdn.net/qq_15122663/article/details/96732890最近有個項目需要java調用C++的動态庫,是以重溫一下操作步驟記錄一下。
使用環境intellij idea clion 系統環境centos:
平時開發使用開發環境是windows 是以部署到linux 上面 調試起來比較麻煩
是以開發jni調試還是挺麻煩的,畢竟開發環境和部署環境不一樣
1.下載下傳linux版本的jdk,linux上面也要安裝jdk環境,不要忘記這一步;
https://www.oracle.com/technetwork/java/javase/downloads/jdk8-downloads-2133151.html- clion需要環境是MinGW,所有下載下傳一個MinGW;
- linux上面安裝 gcc , gcc-c++
- install gcc , gcc-c++ -y
- 把linux版本的jdk裡面檔案夾include的 jni.h , jawt.h 和 linux檔案夾裡面的 jni_md.h , jawt_md.h 複制到 MinGW 的include裡面,順便把這4個檔案放在 gcc安裝檔案夾 include裡面;
環境配置的差不多了,接下來就是代碼部分
首先第一部分就是java代碼
package com.ruan.jni;
public class Jni {
static {
//這個加載絕對路徑動态庫
System.load("/opt/cpp/com_ruan_jni_Jni.so");
}
//實作以下兩個原生方法
public native int add(int a , int b);
public native String print(String msg);
}
編譯将java 生成class檔案
之後将class放在linux環境上,将class檔案生成需要用到的.h頭檔案
現在這個class的包名名是 com.ruan.jni
是以在linux的 根目錄建立 這3級目錄
cd /
mkdir com
cd com
mkdir ruan
cd ruan
mkdir jni
之後将class檔案放在/com/ruan/jni檔案夾下面
下一步就是javah生成.h頭檔案
javah -classpath A -d B -jni C
1
A: com/ruan/jni這三級檔案夾的目錄 我們這裡使用的是根目錄是以是 /
B:輸出檔案的目錄
C:需要編譯的class檔案,這個重點就是一定要加上包名 com.ruan.jni.Jni 後面的class字尾不需要
javah -classpath / -d / -jni com.ruan.jni.Jni
之後就會在根目錄 生成 一個 名稱為 com_ruan_jni_Jni.h頭檔案
/ DO NOT EDIT THIS FILE - it is machine generated /
include
/ Header for class com_ruan_jni_Jni /
ifndef _Included_com_ruan_jni_Jni
define _Included_com_ruan_jni_Jni
ifdef __cplusplus
extern "C" {
endif
/*
- Class: com_ruan_jni_Jni
- Method: add
-
Signature: (II)I
*/
JNIEXPORT jint JNICALL Java_com_ruan_jni_Jni_add
(JNIEnv *, jobject, jint, jint);
- Method: print
- Signature: (Ljava/lang/String;)Ljava/lang/String;
JNIEXPORT jstring JNICALL Java_com_ruan_jni_Jni_print
(JNIEnv *, jobject, jstring);
上面就是生成的頭檔案
頭檔案生成之後就是編寫實作的cpp檔案
第二部分 編寫C++代碼
cpp檔案名稱和.h檔案名稱一樣
com_ruan_jni_Jni.cpp
using namespace std;
JNIEXPORT jint JNICALL Java_com_ruan_jni_Jni_add(JNIEnv *env, jobject job, jint a, jint b) {
jint c;
c = a + b;
return c;
JNIEXPORT jstring JNICALL Java_com_ruan_jni_Jni_print(JNIEnv *env, jobject job, jstring s){
// const char *buf = env->GetStringUTFChars(s , NULL);
char str[] = "歡迎你的到來!";
//字元串拼接,實作strContent+str1,因為strcat的第一個參數必須為非const類型(可變),是以不能直接使用strcat()
//建立一個新的字元串指針
// char strTemp = (char ) malloc(strlen(buf) + strlen(str) + 1);
//拷貝常量到字元串指針
// strcpy(strTemp,buf);
//拼接str1到strTemp
// strcat(strTemp,str);
std::string hello = "Hello from C++";
printf(str);
return env->NewStringUTF(hello.c_str());
// return env->NewStringUTF(str);
上面代碼就是實作原生方法的具體實作方式 緊做參考
現在源碼和頭檔案都有了,接下來就是生成動态庫so檔案
之後将cpp和.h檔案在linux環境生成so檔案
g++ -fPIC -shared -o A B
A:生成動态庫的名稱
B:生成動态庫需要用到的檔案 我們這裡使用的 com_ruan_jni_Jni.cpp和com_ruan_jni_Jni.h
g++ -fPIC -shared -o com_ruan_jni_Jni.so com_ruan_jni_Jni*
後面之是以加入* 因為要加入多個檔案
public class Main {
public static void main(String[] args) {
System.out.println(new Jni().print("測試列印"));
System.out.println(new Jni().add(1 , 2));
}
運作上面的方法就可以輸出列印
不過唯一注意 這個要打包到linux環境上面進行 運作
java -jar xxx.jar
否則會報錯
上面就是簡單的 java 調用C++方式,這個是居于java jni生成的頭檔案進行編寫的so,
但是如果遇到so不是按照jni生成頭檔案提供的接口,那麼這種方式 顯然隻是完成一部分而已,還不能直接使用最原生的C/C++動态庫,那麼最直接的方法,就是在原生的so上面進行封裝一層 按照jni格式的 so 讓java來調用
這種方法 後續有時間再記錄一下,今天到這裡
作者:灰太狼Ruan
來源:CSDN
原文:
版權聲明:本文為部落客原創文章,轉載請附上博文連結!