강좌 & 팁
개인적으로 Android 쪽 개발을 하면서 가장 많이 사용한 부분이 JNI 입니다...
그러나 JNI 문법이 생각보다 까다롭고, 헛갈리는 경우가 많아서...
예제 코드 없이 바로 구현하기는 어려운 경우가 많이 있습니다...
앞으로 회사에서 필요한 경우도 생길 수 있을 것같고, 개인적으로 정리도 할 겸...
JNI programming 에 대한 내용을 조금씩 올려보도록 하겠습니다...
===== (1) hello, world ! ============================================================
1. JNI 란 ?
java native interface 의 약자로 VM 위에서 실행되는 java 프로그램에서 해당 플랫폼의 native code 에 접근할 수 있도록하는 interface 를 말합니다. 주로 c/c++ 로 구현되어 build 된 동적 라이브러리 - so, dll - 와 연동하기 위해 사용됩니다.
2. Java 구현.
- Hello.java : HelloJNI 의 native 함수 printHello() 를 호출하는 main class
public class Hello { public static void main(String[] args) { HelloJNI.printHello(); } } |
- HelloJNI.java : native 함수가 선언된 class, 반드시 static 영역에 loadLibrary() 를 호출해서 class 접근시 library(so) 가 load 되도록 한다.
public class HelloJNI { static { System.loadLibrary("mylib"); } public static native void printHello(); } |
- java compile
$ javac HelloJNI.java $ javac Hello.java |
3. c library 구현.
- JNI header 생성
$ javah -jni HelloJNI |
위의 명령을 실행하고 나면 "HelloJNI.h" 가 생성되는 것을 확인할 수 있다.
- HelloJNI.h
/* DO NOT EDIT THIS FILE - it is machine generated */ #include <jni.h> /* Header for class HelloJNI */ #ifndef _Included_HelloJNI #define _Included_HelloJNI #ifdef __cplusplus extern "C" { #endif /* * Class: HelloJNI * Method: printHello * Signature: ()V */ JNIEXPORT void JNICALL Java_HelloJNI_printHello (JNIEnv *, jclass); #ifdef __cplusplus } #endif #endif |
"HelloJNI.h" 에 해당 class 의 native 함수 - printHello - 에 대한 선언이 되어있음을 알 수 있다. 규칙 익숙해지면 javah 의 도움없이 native 함수의 선언을 할 수 있고, onload 함수를 이용해서 등록하는 방법도 있다.
- HelloJNI.c
#include "HelloJNI.h" #include <stdio.h> JNIEXPORT void JNICALL Java_HelloJNI_printHello(JNIEnv *env, jobject obj) { printf("Hello, world !\n"); } |
HelloJNI.h 에 선언된 Java_HelloJNI_printHello 함수를 구현한다.
- library build
$ gcc -shared -o libmylib.so HelloJNI.c -I/usr/lib/jvm/java-6-openjdk/include/ -I/usr/lib/jvm/java-6-openjdk/include/linux/ |
동적 library 로 빌드함므로 -shared, "jni.h" 에 해당하는 include directory 를 추가해준다.
build 하는 ubuntu PC 에 openjdk 가 설치되어 있어야 한다. ( # apt-get install openjdk-6-jdk )
4. 실행
이제 libmylib.so 를 java "HelloJNI" class 에서 native 함수로 불러서 실행할 수 있다.
library 가 load 될 때 찾을 수 있도록 LD_LIBRARY_PATH 를 추가한다.
$ export LD_LIBRARY_PATH=./ $ java Hello Hello, world ! |
==============================================================================
간단한 hello, world 를 찍는데도 절차가 꽤 복잡한 것같다.
하지만 개발 환경이 어느 정도 구축되면 그렇게 복잡하지만은 않다.