본문 바로가기

Java

JNI 만들기


JNI를 사용하여 c코드 삽입하기

JNI(Java Native Interface)란 자바에서 다른 언어로 만들어진 소스를 접근하여 실행하게 하거나 반대로 다른 언어에서 자바 코드를 접근해서 사용할 수 있도록 하기 위한 하나의 징검 다리 역할을 하는 기법을 말한다.

1. JNI를 사용하기 위한 절차

  • 라이브러리 로딩
  • Native Method를 선언하는 자바 클래스 작성 및 컴파일
  • javah를 사용하여 Native Method가 사용할 헤더 파일 생성
  • C언어로 Native Method 작성 및 컴파일
  • 자바 프로그램 실행

2. JNI 구현 세부 절차

1) 라이브러리 로딩

어떤 native method를 사용할 것인지를 선언해야 하며 이는 Native Method를 동적으로 할당받기 위해 사용되어 진다. 따라서 native method가 구현되기 전에 반드시 선언해야 한다.

또한 클래스가 생성되기 전에 먼저 메모리에 load되어야 하기 때문에 static 블록안에 기술되어야 한다.

static {
     System.loadLibrary("dll 파일명");
}

dll 파일명은 c나 c++로 만들어 dll로 컴파일된 파일이다.

[step 1]

라이브러리 로딩을 하기 위한 코딩 내용.

  1. class HelloJni{
  2.     static {
  3.         System.loadLibrary("Hello");
  4.     }
  5. }

2) Native Method를 선언하는 자바 클래스 작성

메소드 앞에 native 키워드 사용하여 선언하며 일종의 interface 타입이기 때문에 실제 구현 내용은 명시하지 않는다. 실제로 구현되는 내용은 C를 사용하여 구현해야 한다.

public native void prn(int a);

[step 2]

라이브러리 로딩, c에서 사요할 함수, 자바코드에서 함수 호출과정의 코딩 내용

  1. class HelloJni{
  2.     static {
  3.         System.loadLibrary("Hello");
  4.     }
  5.     public native void prn(int  a); // c에서 실제 구현해야 함.
  6.     public static void main(String args[]){
  7.     
  8.         HelloJni hj = new HelloJni();
  9.         hj.prn(100);    
  10.     }
  11. }

prn(int a)과 연결되는 C코드로 숫자 하나를 전달하여 화면에 출력하도록 할 것이다.

[step 3]

위의 자바 코드를 javac를 사용하여 컴파일 한다.

>javac HelloJni.java

[step 4]

Native Method 가 사용할 헤더 파일 생성

c에서 만들 Hello.dll과 상호 연동되어 실행될 파일을 만든다. 즉 Hello.dll이 사용할 헤더 파일을 자바에서 만들게 되는 것이다.

>javah HelloJni

step3과 step4의 실행 결과 3개의 파일이 만들어져 있어야 한다.

HelloJni.java
HelloJni.class
HelloJni.h

[HelloJni.h] 소스 내용

  1. /* DO NOT EDIT THIS FILE - it is machine generated */
  2. #include "jni.h" // 컴파일하기 편하기 수정함.
  3. /* Header for class HelloJni */
  4. #ifndef _Included_HelloJni
  5. #define _Included_HelloJni
  6. #ifdef __cplusplus
  7. extern "C" {
  8. #endif
  9. /*
  10.  * Class:     HelloJni
  11.  * Method:    prn
  12.  * Signature: (Ljava/lang/String;)V
  13.  */
  14. JNIEXPORT void JNICALL Java_HelloJni_prn(JNIEnv *, jobject, jint);
  15. #ifdef __cplusplus
  16. }
  17. #endif
  18. #endif

[step 5]

c언어로 Native Method를 실제 구현해 보자.

  1. // file name : Hello.c
  2. #include "jni.h"
  3. #include "HelloJni.h"
  4. #include <stdio.h>
  5. // 실제 구현해야할 메소드
  6. JNIEXPORT void JNICALL Java_HelloJni_prn(JNIEnv *env, jobject obj, jint value);
  7.     printf("%d\n",value);
  8.    
  9.     return;
  10. }

1) #include <jni.h> 는 자바에서 기본적으로 제공하고 있는 헤더 파일. [JAVA_HOME]/include 디렉토리에 존재하며 컴파일 오류 발생시 현재 디렉토리에 복사하여 사용하여도 무방함.

2) [JAVA_HOME]/include/win32/jni_md.h 도 필요.

3) #include "HelloJni.h" : step4(javah HelloJni)에서 자바로 만든 헤더 파일명.

[step 6]

System.loadLibrary()에서 불러들일 "Hello"라는 라이브러리 만들기

> cl -Ic:\jdk1.4.1_02\include -Ic:\jdk1.4.1_02\include\win32 -LD Hello.c -Fe hello.dll

cl : c 또는 c++컴파일러

-l : jni.h 와 jni_md.h 의 경로(현재 디렉토리에 복사되었으면 생략가능)

-LD : 컴파일할 c 파일명

-Fe : 생성할 라이브러리. 생략가능(System.loadLibrary()의 인자로 사용한 문자열). 생략하면 컴파일한 파일명으로 자동 생성.

만약 라이브러리를 모두 현재 디렉토리에 복사했을 경우 다음과 같이 간단히 기술할 수 있다.

> cl -LD Hello.c

컴파일에 성공하였으면 Hello.dll외 몇 개의 파일을 볼수 있지만 실제로 사용되어 지는 파일은 Hello.dll 뿐이다.

[step 7]

자바 실행

이제 자바 실행파일은 HelloJni.class를 실행하면 printf("%d\n",value)에 의해서 100 이 화면에 출력될 것이다.

> java HelloJni

[응용예]

두수를 전달받아 그 합계를 출력하는 Jni를 만들어 보자.

[1단계]

자바로 아래의 소스를 입력하고 컴파일 한뒤, 헤더 파일을 만들어 보자

  1. // 두수를 C로 전달하고 계산하여
  2. // C로 출력하는 Jni....
  3. // --------------------------------------------------
  4. class SumJni{
  5.     static{
  6.         System.loadLibrary("Sum");
  7.     }
  8.     public native void setValue(int a, int b);
  9.     public native void prnValue();
  10.     
  11.     public static void main(String args[]){
  12.         SumJni sj = new SumJni();
  13.         sj.setValue(40,40);
  14.         sj.prnValue();  
  15.     }
  16. }

[실행]

  • javac SumJni.java
  • javah SumJni

[2단계]

만들어진 SumJni.h를 참고로 C코드를 작성한후 dll파일을 만든다.

  1. #include "jni.h"
  2. #include "SumJni.h"
  3. #include "stdio.h"
  4. int sum=0;
  5. JNIEXPORT void JNICALL Java_SumJni_setValue(JNIEnv *env, jobject obj, jint a, jint b){
  6.     sum = a + b;
  7. }
  8. JNIEXPORT void JNICALL Java_SumJni_prnValue(JNIEnv *env, jobject obj){
  9.     printf("sum=%d\n",sum);
  10. }

  • cl -LD Sum.c

[3단계]

자바의 setValue(int, int)에서 매개변수의 값을 바꾸어 컴파일 한뒤 실행해 보자.

  • javac SumJni.java
  • java SumJni

출처 : http://blog.bagesoft.com/805