라즈베리파이에서 JNI를 사용해보자
먼저 jdk 설치가 되어있어야합니다.
JNI는 C/C++라이브러리를 Java에서 사용할 수 있도록
공유 라이브러리를 만들어주는 기능을 합니다.
JNI의 목적은
코드의 재사용성의 용이함,
성능 향상,
하드웨어 의존적 코드에 대한 문제 해결
입니다.
JNI를 통해 만들어진 C라이브러라는
java코드상에서 Wrapper객체를 통해 호출 될 수 있습니다.
JNI 라이브러리를 만들기 위해서는 Wrapper클래스와
라이브러리용 c파일을 만들어 주어야 합니다.
JNI를 이용한 java용 c library는 다음과같은 순서로 작성됩니다.
1. 함수 선언이 담긴 Wrapper 클래스 작성
2. Wrapper 헤더 생성
3. 함수를 구현한 c코드 작성
4. c코드를 이용해 라이브러리 빌드
5. java코드에서 사용
예제로 문자열을 print하는 간단한 기능으로 구현 하도록 하겠습니다.
먼저 Wrapper클래스입니다.
1 2 3 4 5 6 7 8 9 10 | class Wrapper { //static block static { System.loadLibrary("greeting"); //libgreeting.so } //Native function declaration. public native void print(); } | cs |
wrapper 클래스의 구조는
static 블럭과
Native 함수 정의 부분으로 나누어 집니다.
static블럭에서는 라이브러리를 불러오는 초기화와 같은 역할을 하게 됩니다.
native정의 블럭에서는 사용될 함수의 원형을 작성하게 되는데
이때 native키워드를 사용합니다.
이 Wrapper를 javac를 이용해 컴파일 해줍니다.
$ javac Wrapper.java
코드상 문제가 없다면 .class파일이 생성됩니다.
이것을 javah를 이용해 c에서 사용가능한 헤더로 만들어 줍니다. .class는 붙여주지 않습니다.
$ javah Wrapper
결과물로 Wrapper.h가 생성된 것을 확인하실 수 있습니다.
Wrapper.h입니다.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 | /* DO NOT EDIT THIS FILE - it is machine generated */ #include <jni.h> /* Header for class Wrapper */ #ifndef _Included_Wrapper #define _Included_Wrapper #ifdef __cplusplus extern "C" { #endif /* * Class: Wrapper * Method: print * Signature: ()V */ JNIEXPORT void JNICALL Java_Wrapper_print (JNIEnv *, jobject); #ifdef __cplusplus } #endif #endif | cs |
함수의 선언이 자동으로 만들어집니다.
함수이름 규칙은 아래와 같습니다.
Java_패키지_랩퍼이름_함수이름__인자(JNIEnv *, jobject, ...)
1. Java는 jni를 사용 했다는 접두어 정도로 보시면 될것 같습니다.
2. 패키지이름은 사용하지 않았으므로 생성되지 않았습니다.
3. 랩퍼이름은 우리가 작성한 Wrapper클래스의 이름이 됩니다.
4. 함수의 이름은 Native블럭에서 작성한 함수의 이름입니다.
5. 마지막으로 _2개를 통해 인자의 키워드가 접미어로 붙는데 현재작성한
코드에서는 인자를 받지 않으므로 생성되지 않습니다.
6. 추가적인 인자가 2개 추가됩니다. JNIEnv *와 jobject입니다.
만약 랩퍼 클래스에서 2개의 인자가있었다면,
JNIEnv와 jobject가 추가되어 총 4개의 인자를 받는 형태가 됩니다.
위의 규칙은 c++의 mangling naming과 유사합니다.
여기까지 랩퍼 클래스와 그를 통해 생성된 .h에 대한 작성과 설명이었습니다.
이 헤더 파일을 이용해 c코드를 작성합니다.
작성할 c코드에는 .h에서 만들어졌던 함수의 정의를 작성합니다.
Wrapper.h의 함수를 정의 해줍니다
1 2 3 4 5 6 7 | #include <stdio.h> #include "Wrapper.h" JNIEXPORT void JNICALL Java_Wrapper_print(JNIEnv *env, jobject obj) { printf("Hello, JNI!!\n"); } | cs |
In file included from jni_type.c:2:0:
Wrapper.h:2:17: fatal error: jni.h: No such file or directory
#include <jni.h>
^
compilation terminated.
1 2 3 4 5 6 | class Main { public static void main(String [] args) { Wrapper wrapper = new Wrapper(); wrapper.print(); } } | cs |
사용방식은 wrapper 객체를 생성하고 구현한 함수를 사용하면 됩니다.
작성된 코드를 빌드하고
$ javac Main.java
실행 해줍니다.
$ java Main
Hello, JNI!!
잘 나오는군요!
만약 아래와 같은 애러가 뜬다면 라이브러리 경로가 안잡혀있는겁니다.
Exception in thread "main" java.lang.UnsatisfiedLinkError: no jni_type in java.library.path
at java.lang.ClassLoader.loadLibrary(ClassLoader.java:1857)
at java.lang.Runtime.loadLibrary0(Runtime.java:870)
at java.lang.System.loadLibrary(System.java:1119)
at Wrapper.<clinit>(Wrapper.java:3)
at Main.main(Main.java:3)
아래의 명령을 통해 현재 디렉터리를 라이브러리 디렉터리로 추가해줍니다.
$ export LD_LIBRARY_PATH=.
만약 라이브러리가 다른 디렉터리에 있다면 '.'대신 해당 디렉터리를 써야겟죠!
JNI를 이용한 간단한 라이브러리 작성 끝!
읽어주셔서 감사합니다.
'Linux' 카테고리의 다른 글
[ubuntu] 우분투에서 adb, fastboot 설치하기 (3) | 2015.07.03 |
---|---|
[RaspberryPI] gnu 컴파일러 4.9 설치! (gcc, g++) (0) | 2015.05.12 |
unp.h 사용하기 (2) | 2015.05.06 |
우분투 eth0 고정 ip 설정 (0) | 2015.05.06 |
vim 자동 정렬 하기 (0) | 2015.04.24 |
댓글