天天看點

java 通過jni調用linux so動态庫include ifndef _Included_com_ruan_jni_Jnidefine _Included_com_ruan_jni_Jniifdef __cplusplusendififdef __cplusplusendifendifinclude include include include

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

  1. clion需要環境是MinGW,所有下載下傳一個MinGW;
  2. linux上面安裝 gcc , gcc-c++
  3. install gcc , gcc-c++ -y
  4. 把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

原文:

版權聲明:本文為部落客原創文章,轉載請附上博文連結!