본문 바로가기

카테고리 없음

CDT JNI Project

Eclipse 3.4 & CDT 를 이용한 JNI 프로젝트 예

1. 네이티브 메소드를 호출하는 클래스 생성
자바 프로젝트를 생성하고 자바소스를 다음과 같이 작성한다.

public class Hello {
 
 static {
  System.loadLibrary("libhello"); //libhello.dll 파일을 로드함
 }
 
 public native void displayHelloWorld();

 public static void main(String[] args) {
  new HelloJNI().displayHelloWorld();
 }
}


2. C언어 소스파일에서 include 할 헤더파일(*.h) 생성
위에서 작성한 클래스가 문법상 문제가 없다면 위의 클래스가 저장되면서 컴파일되어 있을 것이다. 커맨드 프롬프트를 하나 열고 컴파일된 클래스파일(*.class) 이 있는 곳으로 이동한다. 그리고 다음과 같이 명령하면 헤더파일(hello.h)이 생성된다.

javah -jni Hello<enter>

3. 생성된 헤더파일(Hello.h)의 내용

/* DO NOT EDIT THIS FILE - it is machine generated */
#include <jni.h>
/* Header for class Hello */

#ifndef _Included_Hello
#define _Included_Hello
#ifdef __cplusplus
extern "C" {
#endif
/*
 * Class:     Hello
 * Method:    displayHelloWorld
 * Signature: ()V
 */
JNIEXPORT void JNICALL Java_Hello_displayHelloWorld
  (JNIEnv *, jobject);

#ifdef __cplusplus
}
#endif
#endif


 javah.exe에 의해 생성된 헤더파일의 함수선언부를 살펴보면,  함수명이 'Java_Hello_displayHelloWorld' 으로 되어 있다. 그러나 윈도우에서는 DLL 파일 생성시 함수명 앞에도 '_' 를 붙이도록 되어 있다고 한다. 그러므로  '_Java_Hello_displayHelloWorld' 처럼 변경해 주어야 한다.

변경된 헤더파일 (hello.h)

/* DO NOT EDIT THIS FILE - it is machine generated */
#include <jni.h>
/* Header for class Hello */

#ifndef _Included_Hello
#define _Included_Hello
#ifdef __cplusplus
extern "C" {
#endif
/*
 * Class:     Hello
 * Method:    displayHelloWorld
 * Signature: ()V
 */
JNIEXPORT void JNICALL _Java_Hello_displayHelloWorld
  (JNIEnv *, jobject);

#ifdef __cplusplus
}
#endif
#endif


4. hello.c 작성
Eclipse에서 C/C++ Project 를 선택하여 프로젝트를 생성한다. 이때 Shared Library형태를 선택하여 DLL파일이 생성될 수 있게 설정해 주어야 한다.
Project Explorer에서 Source Folder(src)를 생성하고 Java 프로젝트에서 생성된 헤더파일(hello.h)파일을 import해 온다.
그 소스 폴더에 다음과 같이 소스파일(hello.c) 파일을 작성한다. 함수명을 헤더파일에서 복사해 붙이는 것이 좋다.

#include <jni.h>
#include "Hello.h"
#include <stdio.h>
JNIEXPORT void JNICALL _Java_Hello_displayHelloWorld
(JNIEnv * env, jobject obj)
{
   printf("Hello world!\n");
   return;
}


지금까지 작성된  내용을 보면 다음과 같다.

사용자 삽입 이미지


5. 헤더 파일의 위치 설정

위의 C 소스를 보면 <jni.h>, "Hello.h" 파일을 임포트하고 있는데, "Hello.h"파일을 동일한 폴더에 있기 때문에 include 패스를 설정해 줄 필요가 없지만, <jni.h> 파일은 JDK가 가지고 있으므로 이 파일이 위치한 경로를 C 컴파일러에게 알려 줄 필요가 있다. 다음과 같이 Include 경로를 설정한다.

C/C++ Project 마우스 우측 > Properties 선택하면 다음곽 같은 설정창이 나타난다.

사용자 삽입 이미지


6. DLL 파일의 이름설정
빌드하기 전에 생성될 DLL파일의 이름을 설정해 주어야 한다. Java소스에서 로드할 DLL 파일의 이름을 libhello 으로 정해놓은 상태이기 때문에 그에 따라서 C/C++프로젝트에도 동일하게 설정해 주어야 한다. 만약 DLL 파일의 이름을 설정해 주지않으면 디폴트로 프로젝트이름이 DLL 파일이름에 포함된다.
Project 위에서 마우스 우측 > Properties 를 선택하여 아래 그림과 같은 창이 나타나면 다음과 같이 설정해 주면 된다.
사용자 삽입 이미지


7. 빌드(DLL 파일생성)
C소스에 포커스가 맞추어져 있는 상태에서 망치모양의 툴을 누르면 컴파일되고 C/C++Project에는 Binaries 노드가 생성되고 그 안에 생성된 DLL 파일의 이름이 보이게 된다.
사용자 삽입 이미지


생성된 DLL 파일을 다음과 같이 확인한다.

사용자 삽입 이미지


8. 자바프로젝트에게 DLL파일의 위치 알려주기
자바 프로그램을 실행하기에 앞서 자바 프로그램이 로드할 DLL 파일의 위치를 알려 주어야 한다. 만약 알려주지 않으면 자바프로그램 실행시 다음과 같은 에러를 발생한다.
사용자 삽입 이미지


자바프로젝트위에서 마우스 우측 > Build Path > Configure Build Path....

사용자 삽입 이미지


다음과 같은 창이 나타났을 때 Native library location:(None)을 선택하고 Edit 버튼을 눌러서 편집해 준다.
사용자 삽입 이미지


로드하고자 한는 DLL파일은 Eclipse Workspace 안에 있기 때문에 다음 창에서 Workspace... 버튼을 눌러서 DLL이 있는 경로를 입력해 주면 된다.
사용자 삽입 이미지


사용자 삽입 이미지


사용자 삽입 이미지


사용자 삽입 이미지




사용자 삽입 이미지


사용자 삽입 이미지



Eclipse를 떠나서 프로그램을 배포할 때는 클래스 파일과 DLL을 동일한 폴더에 두면 된다. 만약 클래스파일과 DLL파일이 다른 폴더에 저장되어 사용되는 환경이라면 System.load("c:/anydir/libhello.dll");와 같이 DLL파일의 절대경로를 사용할 수도 있고, 'java.library.path' Property 에 등록된 폴더에 DLL 파일을 두고 System.loadLibrary("libhello")를 사용하면 된다.

참고로 java.library.path 프로퍼티에 등록되는 경로는 Windows OS에서는 PATH 환경변수에 등록된 경로와 일치한다. 그러므로 PATH환경변수에 등록된 경로에 DLL파일을 저장해 두고 System.loadLibrary("libhello")를 사용하면 자바 시스템은 libhello.dll파일을 PATH환경변수에 등록된 경로에서 찾아서 로드한다는 것이다.

다음과 같은 코드를 통해 현재의 시스템에 설정된 Property들을 모두 확인해 볼 수 있다.
System.getProperties().list(System.out);

다음은 위의 예제 소스를 실행할 당시의 시스템 프로퍼티를 System.getProperties().list(System.out) 를 사용하여 출력해 본 것이다 (Eclipse 에서 실행한 것이므로 Eclipse가 시스템 프로퍼티를 설정한 것도 포함된다)
............................................................................................................................................................................................................................................
-- listing properties --
java.runtime.name=Java(TM) SE Runtime Environment
sun.boot.library.path=C:\Java\jdk1.6.0_06\jre\bin
java.vm.version=10.0-b22
java.vm.vendor=Sun Microsystems Inc.
java.vendor.url=http://java.sun.com/
path.separator=;
java.vm.name=Java HotSpot(TM) Client VM
file.encoding.pkg=sun.io
user.country=KR
sun.java.launcher=SUN_STANDARD
sun.os.patch.level=Service Pack 2
java.vm.specification.name=Java Virtual Machine Specification
user.dir=C:\javaTest\Hello
java.runtime.version=1.6.0_06-b02
java.awt.graphicsenv=sun.awt.Win32GraphicsEnvironment
java.endorsed.dirs=C:\Java\jdk1.6.0_06\jre\lib\endorsed
os.arch=x86
java.io.tmpdir=C:\DOCUME~1\김창운\LOCALS~1\Temp\
line.separator=

java.vm.specification.vendor=Sun Microsystems Inc.
user.variant=
os.name=Windows XP
sun.jnu.encoding=MS949
java.library.path=C:\javaTest\HelloDLL\Debug
java.specification.name=Java Platform API Specification
java.class.version=50.0
sun.management.compiler=HotSpot Client Compiler
os.version=5.1
user.home=C:\Documents and Settings\김창운
user.timezone=
java.awt.printerjob=sun.awt.windows.WPrinterJob
file.encoding=MS949
java.specification.version=1.6
user.name=김창운
java.class.path=C:\javaTest\Hello\bin
java.vm.specification.version=1.0
sun.arch.data.model=32
java.home=C:\Java\jdk1.6.0_06\jre
java.specification.vendor=Sun Microsystems Inc.
user.language=ko
awt.toolkit=sun.awt.windows.WToolkit
java.vm.info=mixed mode, sharing
java.version=1.6.0_06
java.ext.dirs=C:\Java\jdk1.6.0_06\jre\lib\ext;C:\WI...
sun.boot.class.path=C:\Java\jdk1.6.0_06\jre\lib\resources...
java.vendor=Sun Microsystems Inc.
file.separator=\
java.vendor.url.bug=http://java.sun.com/cgi-bin/bugreport...
sun.cpu.endian=little
sun.io.unicode.encoding=UnicodeLittle
sun.desktop=windows
sun.cpu.isalist=pentium_pro+mmx pentium_pro pentium+m...