programing tip

자바에서 c 함수 호출

itbloger 2020. 12. 5. 09:22
반응형

자바에서 c 함수 호출


Java에서 c 함수를 호출하는 방법. c는 컴파일러 기반입니다.

Java에서 Windows의 C 함수를 호출하고 Java에서도 GCC 함수를 호출하고 싶습니다.

어떤 참조?


Java Native Interface : 시작하기를 살펴보십시오 .

2.1 개요

[...] "Hello World!"를 인쇄하기 위해 C 함수를 호출하는 간단한 Java 애플리케이션을 작성하십시오. 이 프로세스는 다음 단계로 구성됩니다.

네이티브 메서드를 선언하는 클래스 (HelloWorld.java)를 만듭니다. javac를 사용하여 HelloWorld 소스 파일을 컴파일하면 HelloWorld.class 클래스 파일이 생성됩니다. javac 컴파일러는 JDK 또는 Java 2 SDK 릴리스와 함께 제공됩니다. 네이티브 메서드 구현을위한 함수 프로토 타입을 포함 javah -jni하는 C 헤더 파일 ( HelloWorld.h) 을 생성하는 데 사용 합니다 . javah 도구는 JDK 또는 Java 2 SDK 릴리스와 함께 제공됩니다. HelloWorld.c네이티브 메서드 의 C 구현 ( )을 작성합니다 . C 구현을 네이티브 라이브러리로 컴파일하여 Hello-World.dll또는 libHello-World.so. 호스트 환경에서 사용 가능한 C 컴파일러 및 링커를 사용하십시오. Java 런타임 인터프리터를 사용하여 HelloWorld 프로그램을 실행하십시오. 클래스 파일 ( HelloWorld.class)과 네이티브 라이브러리 ( HelloWorld.dll또는libHelloWorld.so)는 런타임에로드됩니다. 이 장의 나머지 부분에서는 이러한 단계에 대해 자세히 설명합니다.

2.2 네이티브 메서드 선언

Java 프로그래밍 언어로 다음 프로그램을 작성하여 시작합니다. 이 프로그램은 기본 메서드 인 print를 포함하는 HelloWorld라는 클래스를 정의합니다.

class HelloWorld {
    private native void print();

    public static void main(String[] args) {
        new HelloWorld().print();
    }

    static {
        System.loadLibrary("HelloWorld");
    }
}

HelloWorld 클래스 정의는 인쇄 네이티브 메서드의 선언으로 시작됩니다. 그 뒤에 Hello-World 클래스를 인스턴스화하고이 인스턴스에 대한 인쇄 네이티브 메서드를 호출하는 기본 메서드가 이어집니다. 클래스 정의의 마지막 부분은 인쇄 네이티브 메서드의 구현을 포함하는 네이티브 라이브러리를로드하는 정적 이니셜 라이저입니다.

print와 같은 원시 메소드의 선언과 Java 프로그래밍 언어의 일반 메소드 선언 사이에는 두 가지 차이점이 있습니다. 네이티브 메서드 선언에는 네이티브 수정자가 포함되어야합니다. native 한정자는이 메서드가 다른 언어로 구현되었음을 나타냅니다. 또한 클래스 자체에는 네이티브 메서드에 대한 구현이 없기 때문에 네이티브 메서드 선언은 문 종결 자 기호 인 세미콜론으로 종료됩니다. 별도의 C 파일에서 인쇄 방법을 구현합니다.

기본 메소드 print를 호출하려면 먼저 인쇄를 구현하는 기본 라이브러리를로드해야합니다. 이 경우 HelloWorld클래스 의 정적 이니셜 라이저에서 네이티브 라이브러리를로드합니다 . JVM (Java Virtual Machine)은 HelloWorld클래스의 메소드를 호출하기 전에 자동으로 정적 초기화 프로그램을 실행 하므로 인쇄 기본 메소드가 호출되기 전에 기본 라이브러리가로드됩니다.

HelloWorld클래스 를 실행할 수있는 메인 메소드를 정의합니다 . Hello-World.main일반 메서드를 호출하는 것과 같은 방식으로 기본 메서드 print를 호출합니다.

System.loadLibrary라이브러리 이름을 가져 와서 해당 이름에 해당하는 네이티브 라이브러리를 찾은 다음 네이티브 라이브러리를 애플리케이션에로드합니다. 이 책의 뒷부분에서 정확한로드 프로세스에 대해 설명합니다. 지금 System.loadLibrary("HelloWorld")은 성공하려면 HelloWorld.dllWin32 또는 libHelloWorld.soSolaris에서 호출되는 네이티브 라이브러리를 만들어야 한다는 것을 기억하십시오 .

2.3 HelloWorld 클래스 컴파일

HelloWorld 클래스를 정의한 후 HelloWorld.java 파일에 소스 코드를 저장하십시오. 그런 다음 JDK 또는 Java 2 SDK 릴리스와 함께 제공되는 javac 컴파일러를 사용하여 소스 파일을 컴파일합니다.

 javac HelloWorld.java

이 명령은 HelloWorld.class현재 디렉토리에 파일을 생성합니다 .

2.4 네이티브 메서드 헤더 파일 만들기

우리가 사용하는 다음으로 javah당신은 실행할 수 있습니다 C.에서 네이티브 메소드 구현할 때 유용 JNI 스타일의 헤더 파일을 생성하는 도구를 javahHello-World다음과 같이 클래스를 :

  javah -jni HelloWorld

헤더 파일의 이름은 .h끝에 " "가 추가 된 클래스 이름입니다 . 위에 표시된 명령은라는 파일을 생성합니다 HelloWorld.h. 여기에서는 생성 된 헤더 파일 전체를 나열하지 않습니다. 헤더 파일에서 가장 중요한 부분은 Java_HelloWorld_printHelloWorld.print 메서드를 구현하는 C 함수 인의 함수 프로토 타입입니다 .

 JNIEXPORT void JNICALL   Java_HelloWorld_print (JNIEnv *, jobject);

지금 JNIEXPORTJNICALL매크로를 무시하십시오 . 네이티브 메서드의 해당 선언이 인수를 허용하지 않는 경우에도 네이티브 메서드의 C 구현이 두 개의 인수를 허용한다는 것을 알 수 있습니다. 모든 네이티브 메서드 구현의 첫 번째 인수는 JNIEnv인터페이스 포인터입니다. 두 번째 인수는 HelloWorld객체 자체에 대한 참조 입니다 ( thisC ++ 의 " "포인터 와 유사 함 ). 이 책의 뒷부분에서 JNIEnv인터페이스 포인터와 jobject인수 를 사용하는 방법에 대해 논의 할 것이지만이 간단한 예제에서는 두 인수를 모두 무시합니다.

2.5 네이티브 메서드 구현 작성

에서 생성 된 JNI 스타일 헤더 파일 javah은 네이티브 메서드에 대한 C 또는 C ++ 구현을 작성 하는 데 도움이됩니다. 작성하는 함수는 생성 된 헤더 파일에 지정된 -prototype을 따라야합니다. 다음과 같이 Hello-World.printC 파일에서 메소드를 구현할 수 있습니다 HelloWorld.c.

#include <jni.h>
#include <stdio.h>
#include "HelloWorld.h"   

JNIEXPORT void JNICALL   Java_HelloWorld_print(JNIEnv *env, jobject obj)  {
     printf("Hello World!\n");
     return;
}

이 네이티브 메서드의 구현은 간단합니다. printf 함수를 사용하여 "Hello World!"문자열을 표시합니다. 그런 다음 돌아옵니다. 앞에서 언급했듯이 JNIEnv포인터와 개체에 대한 참조 인 두 인수 는 모두 무시됩니다.

C 프로그램에는 세 개의 헤더 파일이 있습니다.

jni.h-이 헤더 파일은 네이티브 코드가 JNI 함수를 호출하는 데 필요한 정보를 제공합니다. 네이티브 메서드를 작성할 때 항상이 파일을 C 또는 C ++ 소스 파일에 포함해야합니다. stdio.h-위의 코드 스 니펫 stdio.hprintf함수를 사용하기 때문에 포함됩니다 . HelloWorld.h-를 사용하여 생성 한 헤더 파일 javah. 여기에는 Java_HelloWorld_print함수에 대한 C / C ++ 프로토 타입이 포함됩니다 . 2.6 C 소스 컴파일 및 네이티브 라이브러리 생성

파일에 HelloWorld클래스 를 만들 때 HelloWorld.java네이티브 라이브러리를 프로그램에로드하는 코드 줄을 포함했습니다.

 System.loadLibrary("HelloWorld");   

이제 필요한 모든 C 코드가 작성되었으므로이 Hello-World.c네이티브 라이브러리 를 컴파일 하고 빌드 해야합니다 .

운영 체제에 따라 네이티브 라이브러리를 빌드하는 다양한 방법이 지원됩니다. Solaris에서 다음 명령은 libHello-World.so라는 공유 라이브러리를 빌드합니다.

 cc -G -I/java/include -I/java/include/solaris HelloWorld.c -o libHelloWorld.so

-G 옵션은 일반 Solaris 실행 파일 대신 공유 라이브러리를 생성하도록 C 컴파일러에 지시합니다. 이 책의 페이지 너비 제한으로 인해 명령 줄을 두 줄로 나눕니다. 한 줄에 명령을 입력하거나 스크립트 파일에 명령을 넣어야합니다. Win32, 다음 명령은 동적 링크 라이브러리 (DLL) 빌드 HelloWorld.dll은 Microsoft 비주얼 C를 사용하여 ++ 컴파일러를 :

 cl -Ic:\java\include -Ic:\java\include\win32 -MD -LD HelloWorld.c -FeHelloWorld.dll 

The -MD option ensures that HelloWorld.dll is linked with the Win32 multithreaded C library. The -LD option instructs the C compiler to generate a DLL instead of a regular Win32 executable. Of course, on both Solaris and Win32 you need to put in the include paths that reflect the setup on your own machine.

2.7 Run the Program

At this point, you have the two components ready to run the program. The class file (HelloWorld.class) calls a native method, and the native library (Hello-World.dll) implements the native method.

Because the HelloWorld class contains its own main method, you can run the program on Solaris or Win32 as follows:

 java HelloWorld

You should see the following output:

   Hello World! 

It is important to set your native library path correctly for your program to run. The native library path is a list of directories that the Java virtual machine searches when loading native libraries. If you do not have a native library path set up correctly, then you see an error similar to the following:

 java.lang.UnsatisfiedLinkError: no HelloWorld in library path
         at java.lang.Runtime.loadLibrary(Runtime.java)
         at java.lang.System.loadLibrary(System.java)
         at HelloWorld.main(HelloWorld.java) 

Make sure that the native library resides in one of the directories in the native library path. If you are running on a Solaris system, the LD_LIBRARY_PATH environment variable is used to define the native library path. Make sure that it includes the name of the directory that contains the libHelloWorld.so file. If the libHelloWorld.so file is in the current directory, you can issue the following two commands in the standard shell (sh) or KornShell (ksh) to set up the LD_LIBRARY_PATH environment variable properly:

 LD_LIBRARY_PATH=.
 export LD_LIBRARY_PATH

The equivalent command in the C shell (csh or tcsh) is as follows:

 setenv LD_LIBRARY_PATH .

If you are running on a Windows 95 or Windows NT machine, make sure that HelloWorld.dll is in the current directory, or in a directory that is listed in the PATH environment variable.

In Java 2 SDK 1.2 release, you can also specify the native library path on the java command line as a system property as follows:

 java -Djava.library.path=. HelloWorld

The "-D" command-line option sets a Java platform system property. Setting the java.library.path property to "." instructs the Java virtual machine to search for native libraries in the current directory.


In simple terms, just make sure you load the relevant library which contains the function definition, load the library which follows the JNI specification and wraps the target function from the first library, expose native methods from your Java class and you should be good to go.

I'd recommend against raw JNI since it contains a lot of boilerplate code and you would end up cursing yourself if you start wrapping a big C library. By all means do feel free to dabble in JNI when starting out but use something like JNA when it comes to real work.


You options include:

Java Native Interface
see: https://en.wikipedia.org/wiki/Java_Native_Interface

quote:

JNI enables programmers to write native methods to handle situations when an application cannot be written entirely in the Java programming language, e.g. when the standard Java class library does not support the platform-specific features or program library

Java Native Access

see: https://en.wikipedia.org/wiki/Java_Native_Access

quote:

Java Native Access is a community-developed library that provides Java programs easy access to native shared libraries without using the Java Native Interface.

JNR-FFI

see: https://github.com/jnr/jnr-ffi

quote:

jnr-ffi is a java library for loading native libraries without writing JNI code by hand, or using tools such as SWIG.


In the "exotic" category, see NestedVM, which compiles the C to Mips, and runs a Mips VM inside JVM.

http://nestedvm.ibex.org/


Checkout JNAerator. https://code.google.com/p/jnaerator/

You need to provide the source code and preprocessor definitions etc.


If you are using Windows and MinGW gcc you may need additional flag if you are getting UnsatisfiedLinkError for specific method in lib:

gcc -D_JNI_IMPLEMENTATION_ -Wl,--kill-at -I"%JAVA_HOME%"\include -I"%JAVA_HOME%"\include\win32 BestCode.c -shared -o BestCode.dll

JNI - Java Native Interface

In order to call C function from Java you need to use JNI


For making 64-bit compatible dll Remove "-MD" option from statement below

"cl -Ic:\java\include -Ic:\java\include\win32 -MD -LD HelloWorld.c -FeHelloWorld.dll"


I got a solution for this problem. What you need to ensure is you're compiling the code using 64-bit c++ compiler for calling java function running on 64-bit JRE. Along with it we need to save the path of created dll file in "Path" under "Environment variable".


First make ensure to load your native library or .dll file in class path by setting path at property java.library.path

Then use System.loadLibrary()

Do not use .dll extension at the end.

@Jonas gave a very elaborated answer, but I think its also really worth checking this website and you will get all your essential answers there :

http://www.ntu.edu.sg/home/ehchua/programming/java/javanativeinterface.html

It explains how to call a program using JNI :

  • For languages C and C++ or a mixture of both
  • JNI without any parameters, primitives, strings or Array of primitives
  • Accessing object variables, callback instances methods and much more.

참고URL : https://stackoverflow.com/questions/5963266/call-c-function-from-java

반응형