JNI in solaris

JNI in solaris

jni 사용해 본 경험은 android에서 간단하게 테스트 한 정도에 불과했는데,
이번 프로젝트 진행중에 java에서 SHM을 C++ 라이브러리를 이용하기 위해 구현했다.
tutorial 형식으로 인터넷에 많이 있지만, 이번에 프로젝트에 적용한 방법을 정리했다.

1. 간단하게 실행할  java 파일을 생성하자.
JNITest.java

 

2. java에서 C/C++을 호출할 클래스를 생성하자.

Dailyon.java

여기에서 C/C++로 호출할 메소드 앞에 native 를 붙여주고,
System.loadLibrary(“dailyon”); 로딩할 라이브러리 이름을 지정해준다.
unix/linux 계열은 파일명이 libdailyon.so 가 된다.

3. javac Dailyon.java
만들 파일을 컴파일 하고

4. javah Dailyon
위와 같이 해주면 Dailyon.h 파일이 생성된다.

Dailyon.h

 

5. Dailyon.cpp 파일 작성
위에서 만들어진 파일 기반으로 c/cpp 파일을 작성하자.

Dailyon.cpp

 

Java_dailyon_hello 인수와 리턴형 void 이기 때문에 크게 문제가 없고,
Java_dailyon_bye 스트링으로 인수를 받고, int 형으로 리턴한다.

따라서 jstring 받은 형태를 char * 변환하는 부분을 주목하자.
const char * pcInput = _env->GetStringUTFChars(_str, NULL);
cout << “[C++] Input[” << pcInput << “]” << endl;

메소드명에 짐작하겠지만, UTF-8 형태로 인코딩된다.
따라서 euc-kr이 필요하다면, 별도의 변환이 필요하다.

6. C/C++ libdailyon.so 컴파일
필자는 g++로 컴파일 하였다.
원래 사용하던 makefile이 있었는데, 이상하게 잘 안되어서 아래와 같은 옵션을 사용하였다.
g++ -Wno-deprecated -I$SERVER_HOME/include -I$SERVER_HOME/lib -I$ORACLE_HOME/precomp/public -I$ORACLE_HOME/rdbms/demo -I$ORACLE_HOME/rdbms/public
-I$JAVA_HOME/include -I$JAVA_HOME/include/solaris -G He
lloNative.cpp -o libdailyon.so

-I$JAVA_HOME/include/solaris 부분은 운영체제에 따라서 위치가 다르니 주의하자.

다음과 같은 명령어로 상태를 확인해보자.
ldd libdailyon.so
nm -C libdailyon.so | grep UNDEF
ld libdailyon.so

여기까지 별탈없이 진행되었다면,
javac JNITest.java
java JNITest 하면, 화면에 텍스트가 출력될것이다.

7. 사용자 라이브러리 추가
순수 C++로 만든 사용자 라이브러리 libmylib.so 추가해 보자.

Myclass.h

 

MyClass.cpp

 

8. libmylib.so 컴파일
이때는 이전에 사용했던 makefile을 사용해도 무방하다.

9. libdailyon.so 컴파일
g++ -Wno-deprecated -I$SERVER_HOME/include -I$SERVER_HOME/lib -I$ORACLE_HOME/precomp/public -I$ORACLE_HOME/rdbms/demo -I$ORACLE_HOME/rdbms/public
-I$JAVA_HOME/include -I$JAVA_HOME/include/solaris -lmylib -G He
lloNative.cpp -o libdailyon.so

-lmylib 만 추가해 주고 컴파일만 하면 된다.

마찬가지로 아래 명령어로 상태를 확인하자.
ldd libdailyon.so
nm -C libdailyon.so | grep UNDEF
ld libdailyon.so

아래는 실제 프로젝트에서 사용한 예)
g++ -Wno-deprecated -I$SERVER_HOME/include -I$SERVER_HOME/lib -I$ORACLE_HOME/precomp/public -I$ORACLE_HOME/rdbms/demo -I$ORACLE_HOME/rdbms/public
-I$JAVA_HOME/include -I$JAVA_HOME/include/solaris -lclntsh -lipc -lreactor -lutil++ -lhash -lsock++ -lservice -ldbtable -lvoipmisc -lmyclass -G He
lloNative.cpp -o libdailyon.so

 

 

2011-10-27 추가
어제 console 상에서는 잘 되었는데, servlet에서 실행이 안되어서 하루종일 머리 뜯으면서 씨름했는데
원인은 패키지 때문이었다.
가령 동일한 클래스 명을 구분해주기 위해서 java에서는 패키지를 사용하는데,
jni로 구현할때 함수명과 매핑되는 규칙이 있다.

Dailyon 클래스 내의  hello 메소드
default package: Java_Dailyon_hello
jni package: Java_jni_Dailyon_hello
와 같이 함수명에 패키지 이름이 추가 된다.

따라서 aaa.bbb.ccc 패키지라면, Java_aaa_bbb_ccc_함수명이 된다.

헤더 파일을 생성할때도 다음과 같은 순서로 진행한다.
javac jni/Dailyon.java
컴파일 하고,
javah jni.Dailyon
으로 헤더 파일을 생성한다.

그러면 jni_Dailyon.h 파일이 생성되고,
파일 내부는  Java_jni_Dailyon_함수명() 형태를 가진다.

 

Leave a Reply

Your email address will not be published. Required fields are marked *