5.5. ハローワールド (JNA)

Java Native Accessの実装例を見てみましょう。

まず実装するのは OpenCL ライブラリを使用した C 言語のソースコードです。

HelloJNA.c. 

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <OpenCL/cl.h>
#include <assert.h>

int square(int num) {
        return num*num;
}

int squareArray(int* num) {
        int i,sum = 0;
        for(i = 0; i<3; i++) {
                num[i] *= num[i];
                sum += num[i];
        }
        return sum;
}

const char* helloReply(const char* msg) {
        printf("%s\n",msg);
        msg = "I'm from C language!";
        return msg;
}

const char* checkDevice() {
        cl_platform_id platform;
        cl_device_id *devices;
        cl_uint num_devices;
        cl_int i, err;
        char *name_data = malloc(sizeof(char)*48);
        err = clGetPlatformIDs(1,
                        &platform, NULL);
        if(err < 0) {
          perror("failed to find platforms");
          exit(1);
        }
        err = clGetDeviceIDs(platform,
                        CL_DEVICE_TYPE_ALL,
                        1, NULL, &num_devices);
        if(err < 0) {
          perror("Failed to find devices");
          exit(1);
        }
        devices = (cl_device_id*)
                 malloc(sizeof(cl_device_id) * num_devices);
        clGetDeviceIDs(platform,
                        CL_DEVICE_TYPE_ALL,
                        num_devices,
                        devices, NULL);

        for(i=0; i<num_devices; i++) {
          err = clGetDeviceInfo(devices[i],
                          CL_DEVICE_NAME,
                        sizeof(char)*48, name_data, NULL);
          if(err < 0) {
                  perror("Failed to read device name");
                  exit(1);
          }
          printf("CL_DEVICE_NAME: %s\n",name_data);
          clReleaseDevice(devices[i]);
        }

        free(devices);
        return name_data;
}

void destroy(char* data) {
        assert(NULL != data);
        free(data);
}

このソースコードは OpenCL ライブラリを使った C 言語でストレートに実装しています。

ヘッダーファイルを作らないといけない JNI に比べるとこれは大きな利点となります。

次に Java サイドの実装を見てみましょう。

JNAの実装の基本部分は「com.sun.jna.Library」を実装したインターフェースを作ることからはじめます。

インターフェース内に、C言語のソースで定義した関数に対応したメソッドを宣言します。

最後にインターフェースのインスタンスを生成して、メソッドを呼び出せば一連の実装は完了となります。

HelloJNA.java. 

package com.book.jocl;

import com.sun.jna.Library;
import com.sun.jna.Native;
import com.sun.jna.Pointer;
import com.sun.jna.PointerType;
import com.sun.jna.ptr.ByteByReference;

interface HelloLib extends Library { //(1)
        HelloLib Instance = (HelloLib) Native.loadLibrary("hello", HelloLib.class); //(2)

        ByteByReference checkDevice(); //(3)
        int square(int num);
        int squareArray(int[] array);
        ByteByReference helloReply(String msg);
        void destroy(Pointer ptr);
}

public class HelloJNA {

        public static void main(String[] args) {
                HelloLib hello = HelloLib.Instance; //(4)
                ByteByReference dev_info = hello.checkDevice(); //(5)
                Pointer dev_ptr = dev_info.getPointer(); //(6)
                String dev_str = dev_ptr.getString(0); //(7)
                System.out.println("checkDevice function returns: "+dev_str);
                hello.destroy(dev_ptr); //(8)

                int squared = hello.square(5);
                System.out.println(squared);
                int squaredArray[] = new int[10];
                for(int i =0; i < 3; i++) {
                        squaredArray[i] = i+1;
                }
                int returnedSquare = hello.squareArray(squaredArray);
                System.out.println(returnedSquare);
                ByteByReference reply = hello.helloReply("Hello World! JNA!");
                Pointer ptr = reply.getPointer();
                String str = ptr.getString(0);
                System.out.println(str);

        }

}

(1)

JNAインターフェースはLibraryクラスを継承します。

(2)

hello.dll、libhello.so、libhello.dylibを検索して、ネイティブライブラリの関数を指すポインタを作ります。

(3)

ネイティブライブラリの関数プロトタイプを宣言します。

(4)

インターフェースのインスタンスを取得します。

(5)

メンバー関数を呼び出します。

(6)

ByteByReferenceからポインタを取得します。

(7)

ポインタから文字列を取得します。

(8)

確保したメモリ領域を解放します。

Copyright 2018-2019, by Masaki Komatsu