우선 간단한 자바 클래스를 작성합니다.
[HelloWorld.java]
import java.io.*;
public class HelloWorld {
public native void printMessage(); // native call을 할 함수명입니다.
static {
System.loadLibrary("hello"); // native call 함수가 들어있는 라이브러리 이름입니다.
}
public static void main(String[] ar) {
HelloWorld hello = new HelloWorld();
hello.printMessage(); // native call 호출
}
}
위에서 작성한 자바 소스를 컴파일합니다.
[root@localhost]# javac HelloWorld.java
이렇게 되면 HelloWorld.class라는 파일이 생성됩니다.
그리고 Native Method가 사용할 헤더파일을 생성합니다.
[root@localhost]# javah -jni HelloWorld
아래와 같은 HelloWorld.h 파일이 생성됩니다.
[HelloWorld.h]
/* DO NOT EDIT THIS FILE - it is machine generated */
#include <jni.h>
/* Header for class HelloWorld */
#ifndef _Included_HelloWorld
#define _Included_HelloWorld
#ifdef __cplusplus
extern "C" {
#endif
/*
* Class: HelloWorld
* Method: printMessage
* Signature: ()V
*/
JNIEXPORT void JNICALL Java_HelloWorld_printMessage (JNIEnv *, jobject);
#ifdef __cplusplus
}
#endif
#endif
#include <jni.h>
/* Header for class HelloWorld */
#ifndef _Included_HelloWorld
#define _Included_HelloWorld
#ifdef __cplusplus
extern "C" {
#endif
/*
* Class: HelloWorld
* Method: printMessage
* Signature: ()V
*/
JNIEXPORT void JNICALL Java_HelloWorld_printMessage (JNIEnv *, jobject);
#ifdef __cplusplus
}
#endif
#endif
이 파일을 바탕으로 실제 Native Method를 작성합니다.
[HelloWorld.c]
#include "HelloWorld.h"
/*
* Class: HelloWorld
* Method: printMessage
* Signature: ()V
*/
JNIEXPORT void JNICALL Java_HelloWorld_printMessage (JNIEnv *env, jobject me)
{
/*
* Class: HelloWorld
* Method: printMessage
* Signature: ()V
*/
JNIEXPORT void JNICALL Java_HelloWorld_printMessage (JNIEnv *env, jobject me)
{
while(1)
printf("Helo World!!!\n");
return;
}
여기까지 오면 HelloWorld.java, HelloWorld.class, HelloWorld.h, HelloWorld.c 까지 만들어집니다.
그리고 Native Method가 들어간 라이브러리를 컴파일합니다.
gcc -g -I/usr/local/java/include -I/usr/local/java/include/linux -shared HelloWorld.c -o libhello.so
분홍색 : 디버깅을 위한 옵션(일반적인 경우 뺀다)
빨간색 : jni.h 경로
파란색 : jni_md.h 경로
녹색 : Shared Library를 사용하는 옵션
노란색 : 소스파일
보라색 : 컴파일된 라이브러리 파일명(HelloWorld.java의 loadLibrary에서는 loadLibrary("hello")만 하면된다)
jni.h, jni_md.h의 경로는 설치된 jdk의 경로에 따라 달라질 수 있으므로 경로를 검색하여 자신의 환경에 맞게 바꿔줍니다.
[root@localhost]# find / -name "jni.h"
[root@localhost]# find / -name "jni_md.h"
이제 Native Method 라이브러리까지 작성되었습니다. 실행을 해봅니다.
[root@localhost]# java HelloWorld
보통은 원하는 문자가 바로 나오지만 아래와 에러 메세지를 나타내는 경우도 있습니다.
java.lang.UnsatisfiedLinkError: no hello in java.library.path at java.lang.ClassLoader.loadLibrary(ClassLoader.java:1709) at java.lang.Runtime.loadLibrary0(Runtime.java:823) at java.lang.System.loadLibrary(System.java:1030) at HelloWorld.<clinit>(HelloWorld.java:<line number>) Could not find the main class: HelloWorld. Program will exit.
라이브러리의 위치가 제대로 지정이 되어 있지 않아서 나타나는 문제입니다.이럴때는 아래와 같이 입력해줍니다.
[root@localhost]# chcon -t texrel_shlib_t libhello.so
실행을 해봅니다.HelloWorld가 무한 반복되는 것을 볼 수 있습니다. 이 상황에서 다른 터미널을 더 열어서현재 진행중인 HelloWorld의 pid를 알아냅니다.
[root@localhost]# ps -ax
해당 프로세스의 pid가 18942라면 이 값을 가지고 GDB를 실행합니다.
[root@localhost]# gdb -p 18942
무한반복중인 프로세스가 멈추고 gdb가 실행됩니다.gdb 명령은 다른 글을 참고하세요ps. 현재 진행중인 프로세스를 멈췄으므로 디버깅을 계속 진행할 때 아래와 같이 run 대신 continue를 입력합니다.
(gdb) continue