2021年8月12日 星期四

linux 上是使用 kolinc-jvm 編譯 kotlin 程式, 程式透過 jni 呼叫原生 c 函式

 1. 上官網 https://github.com/JetBrains/kotlin/releases/download/v1.5.21/kotlin-compiler-1.5.21.zip下載 kotlin 編譯器, 開啟終端機進入下載目錄, 將它解壓縮到目錄 kotlinc 內

       cd  Downloads  &&  unzip  kotlin-compiler-1.5.21.zip

2.  安裝 openjdk 11, 將程式安裝到 /usr/lib/jvm/java-11-openjdk-amd64

       sudo  apt-get  install  openjdk-11-jdk

3. 建一個專案 project 目錄(mkdir project), 在裏面編寫一個 Makefile 方便編譯及跑程式:
buildDir  = build
main_jar  = $(buildDir)/main.jar
jniLib_jar= $(buildDir)/jniLib.jar
libjni_so = $(buildDir)/libnative.so

jdk11     = /usr/lib/jvm/java-11-openjdk-amd64/include
openjdk   = -I$(jdk11)  -I$(jdk11)/linux
opencv2   = `pkg-config  --cflags  --libs  opencv4`

kotlinDir =  /home/mint/Downloads/kotlinc
ktc       = $(kotlinDir)/bin/kotlinc  -include-runtime
coroutine = -cp $(kotlinDir)/lib/kotlinx-coroutines-core.jar

javaLib   = $(coroutine):$(jniLib_jar)
cppLib    = -shared  -fPIC  $(openjdk)  $(opencv2)

run: main  native
    java  -Djava.library.path=$(buildDir)  $(javaLib):$(main_jar)  MainKt

main:  $(buildDir)  $(main_jar)

native: $(libjni_so)

$(main_jar): main.kt  $(jniLib_jar)
    $(ktc) -d  $@  $<  $(javaLib)

$(jniLib_jar): jniLib.kt
    $(ktc) -d  $@  $<  $(coroutine)

$(libjni_so): cpp/native.cpp
    g++  -o  $@  $<  $(cppLib)

$(buildDir):
    [ -d $@ ] || mkdir $@ && echo $@ exist already

clean:
    [ -d $(buildDir) ] || echo $(buildDir) not exist && rm -rf $(buildDir)

4. 在專案目錄內寫一個 kotlin 主程式碼 main.kt:

import  kotlinx.coroutines.*
import  jniLib.*
fun  main( ) {
  runBlocking{
     GlobalScope.launch(Dispatchers.IO) { // split nonblocking coroutine
          println("coroutine hello1")
     }
     NativeClass( ).hello( ) // call  jni  c  routine
  }
}

5.  在專案目錄內寫一個 kotlin 介面程式庫 jniLib.kt:

package jniLib
class NativeClass {  
  external fun hello( ) // external  function written in c++ language
  init {
      System.loadLibrary("native")
  }
}

6. 在專案目錄內再建個 cpp 子目錄(mkdir  cpp), 在 cpp 目錄內編寫一個用 c 寫的 jni  程式碼 cpp/native.cpp:

#include <stdio.h>
#include <jni.h>
#include <opencv2/opencv.hpp>
#include <opencv2/highgui.hpp>
const char *window = "mouseEvent";
void mouseEvent(int event, int x, int y, int flags, void *args){
    static cv::Scalar green(0,   255,   0);
    static cv::Scalar red(0,   0,   255);
    cv::Mat &image = *(cv::Mat *)args;
    switch(event) {
        case cv::EVENT_LBUTTONDOWN: // left mouse button click
                printf("left   click row: %d, col: %d\n", x, y);
                cv::circle(image, cv::Point(x, y), 2, red);
                cv::imshow(window, image);
                break;
        case cv::EVENT_RBUTTONDOWN:// right mouse button click
                printf("right  click row: %d, col: %d\n", x, y);
                cv::line(image, cv::Point(0, 0), cv::Point(x, y), green, 2, cv::FILLED);
                cv::imshow(window, image);
                break;
        case cv::EVENT_MBUTTONDOWN:// middle mouse button click
                printf("middle click row: %d, col: %d\n", x, y);
                break;
        case cv::EVENT_MOUSEMOVE:// mouse movment
                // printf("mouse move  row: %d, col: %d\n", x, y);
                break;
    }
}
extern "C" {
    JNIEXPORT void JNICALL Java_jniLib_NativeClass_hello(JNIEnv *env, jobject obj) {        
        cv::Mat fg(800, 800, CV_8UC3);// w x h
        cv::namedWindow(window, cv::WINDOW_NORMAL);
        cv::setMouseCallback(window, mouseEvent, &fg);
        cv::imshow(window, fg);
        cv::waitKey(0);//press any key to exit
    }
}

上述步驟 3,4,5,6 存檔後, 在專案目錄內開啟終端機執行 make run 跑看看, 不用 Gradle, 速度快多了

後記: 使用 cmake 語法, 編譯 c++ 動態程式庫 libnative.so:

1. 先在專案目錄內, 編輯一個 CMakeLists.txt:
cmake_minimum_required(VERSION 3.10.2)
project(native)
include_directories(
    /usr/lib/jvm/java-11-openjdk-amd64/include
    /usr/lib/jvm/java-11-openjdk-amd64/include/linux
    /usr/include/opencv4
)
set(opencvLib   -lopencv_core   -lopencv_highgui   -lopencv_imgproc)
add_library(native   SHARED   cpp/native.cpp)
target_link_libraries(native   PUBLIC   ${opencvLib})

2. 建一個子目錄 build, 在裏面執行 cmake .. 產生 Makefile, 接著 make 就能生成 libnative.so:
    [ -d build ] || mkdir   build
    cd   build   &&   cmake  ..  &&  make

沒有留言:

張貼留言

使用 pcie 轉接器連接 nvme SSD

之前 AM4 主機板使用 pcie ssd, 但主機板故障了沒辦法上網, 只好翻出以前買的 FM2 舊主機板, 想辦法讓老主機復活, 但舊主機板沒有 nvme 的界面, 因此上網買了 pcie 轉接器用來連接 nvme ssd, 遺憾的是 grub2 bootloader 無法識...