[문서]
1차 수정 :2015-08-16: [참고]항목 넣음
2차 수정 :2015-08-16: Linux 에서 JNI수행하는 방법 추가.
3차 수정 :2015-08-16: [참고]->[이슈] 수정
[개념]
JNI 는 Java Native Interface의 약자로 Java 에서 다른 언어의 코드의 수행을 돕는 interface 이다.
이를 통해 특히 c/c++와 연동하여 빠른 수행을 적용할 수 있다. 그러나 보안의 문제와 이식의 문제를 야기시킴.
(안드로이드에서는 ndk 를 이용)
[수행 목표]
Android에서 JNI 수행 실패
-> Window 64bit 에서 JNI 수행
-> Linux 32bit 에서 JNI 수행
[수행환경]
-윈도우
intel 64bit cpu
window 7
mingw 32 ( 말미에 mingw 64 설치) : dll 생성 및 compile을 위해 필요. (dll 생성 : dlltool.exe , compile : mingw64)
cygwin 64
jdk 1.8.0.51 설치 (2015-08-16)
-리눅스
CentOS 6.5 32bit
(gcc는 당연히 있음)
jdk 1.8.0.51 설치(2015-08-16)
[일지]
2015-08-14: JNI 무작정 수행 (android에서) javah로 만드는 .h 파일 생성 실패 (원인 : compile을 못함(class 파일생성안하고 수행))
-> 컴파일이 안되는데 어떡함. 결국 해결 못함 수 번의 삽질끝에 포기.
2015-08-16: Window에서 JNI 수행하기로 마음먹음 계속된 실패 (원인 : java에서 path 설정을 못함.(JAVA_HOME을 이용한 옵션 주는 방법 잘 못함.)
-> 해결방법 : 절대경로로 잡음. (이때서야 javac javah gcc 기타 등등 의 path가 중요하다는걸 깨달음)
2015-08-16: compile 에러 발견 (library 에러) -> 순서(*1)에 맞게 재 컴파일 후 사라짐
2015-08-16: compile 성공후 실행에서 에러 (64 bit 에러) -> gcc 가 64비트용이 아니라 32비트였음
2015-08-16: 64bit gcc 를 위해 mingw64 설치 후 64bit compile용 prompt 로 이전 gcc의 compile수행 후 예제 수행 성공.
초기 필요 파일 : HelloNative.java, jni.h , jni_md.h (+ HelloNative.c)
주의 : 파일 생성 중에 만들어지는 파일명은 알아서 정하도록.
-HelloNative.java
class HelloNative
{
native public static void hello();
static
{
System.loadLibrary("HelloNative");
}
}
class HelloNativeTest
{
public static void main(String[] args)
{
HelloNative.hello();
}
}
- HelloNative.c ($javah HelloNative수행 후 .c 작성하면 된다.)
#include <stdio.h>
#include "HelloNative.h" // 이놈은 위의 .java 완성후 $javah HelloNative 하면 만들어지는 파일.
JNIEXPORT void JNICALL Java_HelloNative_hello(JNIEnv *env, jclass cls)
{
printf("This JNI Hello!\n");
}
[수행 요약]
전제 1 : 현재 수행과정 위치는 c:\dev
전제 2 : jni.h 와 jni_md.h 를 내가 수행하고자하는 폴더에 넣는다.
ex) jni.h(from java/jdk(약식)/include 폴더에 있음)와 jni_md.h (from java/jdk(약식)/include/win32) 를 가져와서 c:\dev\에 넣어 놓음.
관련된 참고 예제 : [Mark Allen Weiss] JNI:JAVA와 C 의 연동.pdf
주의 1 : 각 compiler의 절대 위치 알기!!!!!!!!!
jdk 절대 위치(java, javac, javah 수행을 위해) , mingw 절대 위치(gcc, dlltool 수행을 위해) 반드시 알아야함.
주의 2 : 예제는 위의 참고 예제!!!!!!
주의 3 : native 단의 메소드의 수행 환경이 어디인지 알기 (64비트 인지... 32비트인지)
권장 1 : 동적 라이브러리 개념 알고 수행하길 바람
생성 순서 : .java -> .class -> .h -> .c -> .o ->(.def ->( .a + 이전의 .o )->) .dll
다시한번 말하지만 수행 위치는 c:\dev 임
1단계 : java 코드 작성.
(.java 생성)
2단계 : HelloNative.java 파일 compile
(명령어 javac 수행) -> .class 파일 생성
$javac HelloNative.java
3단계 : HelloNative.h 파일 생성
(명령어 javah 로 수행, class 파일 존재해야함)
$javah HelloNative
4단계 : .c 파일 작성
(native 단의 메소드 구현을 여기서 수행, 위의 .h 파일 include하는 .c 파일임)
$vi HelloNative.c (위처럼) 작성
주의 : parameter에 변수명 꼭 넣자.
5단계 : .o 파일 생성
(해당 .c 파일 compile 수행 결과, 64bit 윈도우 라면 -m64 옵션 줘야함. )
$gcc -c HelloNative.c -o HelloNative.o -Ic:\dev -Ic:\dev -m64
-I(대문자 i) 옵션 : jni.h , jni_md.h 위치를 말해줌.
6단계 : 동적라이브러리 파일 생성
-윈도우(6단계)
(.o 파일에 대한 동적라이브러리 파일로 linux는 .so 윈도우는 .dll)
6단계 요약 (yyy.o 파일 -> .dll 관련된 .def 파일 생성 -> 라이브러리 .a 파일 생성 -> .dll 파일 생성)
6-1단계 : $dlltool --output-def xxx.def --kill-at --dllname bbb.dll yyy.o // .def 생성
6-2단계 : $dlltool --output-lib libXYZ.a --input-def xxx.def --kill-at --dllname bbb.dll yyy.o
6-3단계 : $gcc yyy.o -o bbb.dll -m64 -Wall -L -IXYZ -shared (여기서 -I 는 대문자 i 그리고 libXYZ.a 에서 lib 생략하는건 약속. 자동으로 lib 읽음)
최종 bbb.dll 생성
-리눅스(6단계)
$gcc -shared -o libXYZ.so yyy.o 로 끝
주의 :
여기서 LD_LIBRARY_PATH 설정을 해줘야함.
이 설정은 /etc/profile 맨 밑에서 적용할 수 있음.
적용하지 않으면 java.lang.UnsatiedLinkError: no XX in java.library.path 에러 뜸
해결 방법 :
/etc/profile 을 수정.(여기서 마지막 라인에 export LD_LIBRARY_PATH =./ 넣거나
export LD_LIBRARY_PATH = 현재 내가 쓰려는 .so 가 있는 폴더 경로를 써주면 됌)
최종 bbb.so 생성
7단계 :java실행
(명령어 java 로 수행)
#?추측컨데 리눅스 환경에서 하려면 5 단계 까지는 유사하고 6단계에서 .so 파일만 생성하면 다 될 듯?
#?안드로이드의 경우 .apk 로 존재하는데 어떻게 .so 와 .class 가 작동하지?
#! gcc -fPIC 하면 include 하는 위치의 설정이 바뀜... ( stdio.h 에러가 나기도함. 옵션의 정확한 기능은 검색 요망)
#? JVM 에서 .dll 또는 .so 가 어떻게 실행되는지... native 함수의 경우에도 어떻게 수행되는지 그 로직을 알아내자.
#? Java 말고 android 에선 어떻게 해야하지? 그리고 path 설정이 복잡할 것으로 우려됨. (지랄스러울 듯)
[이슈]
LD_LIBRARY_PATH 이슈 : http://jetzt.tistory.com/332
DLL 만들기 : http://mamma.tistory.com/32
선택한 JNI 예제 : http://openshareit.tistory.com/entry/JNI-%EC%A2%85%EA%B2%B0%EC%9E%90-%EB%AC%B8%EC%84%9C
parameter 이슈 : http://stackoverflow.com/questions/4611365/compiling-c-file-that-uses-jni-h
linux 환경 변수 설정 이슈 : /etc/profile 수정
윈도우 환경 변수 설정 이슈 : PATH 설정(javah 있는 위치, gcc 있는 곳)
jni.h , jni_md.h 위치 이슈 : 개발 중인 폴더에 옮김