web-dev-qa-db-ja.com

Javaからc関数を呼び出す

Javaからc関数を呼び出す方法。 cはコンパイラベースのようです。

JavaからWindowsのC関数を呼び出し、GCC関数fron Javaも。

参照はありますか?

60
Wen

Java Native Interface:Getting Started をご覧ください。

2.1概要

[...]簡単なJava「Hello World!」を出力するC関数を呼び出すアプリケーションを記述します。プロセスは次のステップで構成されます。

ネイティブメソッドを宣言するクラス(HelloWorld.Java)を作成します。 javacを使用してHelloWorldソースファイルをコンパイルし、クラスファイルHelloWorld.classを作成します。 javacコンパイラはJDKまたはJava 2 SDKリリースで提供されます。javah -jniを使用して、ネイティブメソッド実装の関数プロトタイプを含むCヘッダーファイル(HelloWorld.h)を生成します。javahツールはJDKで提供されますまたはJava 2 SDKリリース。ネイティブメソッドのC実装(HelloWorld.c)を記述します。C実装をネイティブライブラリにコンパイルし、Hello-World.dllまたはlibHello-World.soを作成します。ホスト環境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クラスの定義は、printネイティブメソッドの宣言で始まります。この後に、Hello-Worldクラスをインスタンス化し、このインスタンスの印刷ネイティブメソッドを呼び出すメインメソッドが続きます。クラス定義の最後の部分は、print nativeメソッドの実装を含むネイティブライブラリをロードする静的初期化子です。

Printなどのネイティブメソッドの宣言と、Javaプログラミング言語の通常のメソッドの宣言。2つの違いがあります。ネイティブメソッドの宣言には、ネイティブ修飾子が含まれている必要があります。このメソッドは別の言語で実装されています。また、クラス自体にはネイティブメソッドの実装がないため、ネイティブメソッド宣言はセミコロン、ステートメント終了記号で終了します。別のCファイルにprintメソッドを実装します。

ネイティブメソッドprintを呼び出す前に、printを実装するネイティブライブラリをロードする必要があります。この場合、HelloWorldクラスの静的初期化子にネイティブライブラリをロードします。 Java仮想マシンは、HelloWorldクラスのメソッドを呼び出す前に静的初期化子を自動的に実行します。これにより、ネイティブメソッドの呼び出し前にネイティブライブラリが確実にロードされます。

HelloWorldクラスを実行できるようにメインメソッドを定義します。 Hello-World.mainは、通常のメソッドを呼び出すのと同じ方法でネイティブメソッドprintを呼び出します。

System.loadLibraryはライブラリ名を取得し、その名前に対応するネイティブライブラリを見つけ、ネイティブライブラリをアプリケーションにロードします。正確な読み込みプロセスについては、本の後半で説明します。今のところ、System.loadLibrary("HelloWorld")が成功するためには、Win32ではHelloWorld.dll、SolarisではlibHelloWorld.soと呼ばれるネイティブライブラリを作成する必要があることを思い出してください。

2.3 HelloWorldクラスのコンパイル

HelloWorldクラスを定義したら、ソースコードをHelloWorld.Javaというファイルに保存します。次に、JDKに付属のjavacコンパイラまたはJava 2 SDKリリースを使用してソースファイルをコンパイルします。

 javac HelloWorld.Java

このコマンドは、現在のディレクトリにHelloWorld.classファイルを生成します。

2.4ネイティブメソッドヘッダーファイルの作成

次に、javahツールを使用して、Cでネイティブメソッドを実装するときに役立つJNIスタイルのヘッダーファイルを生成します。次のように、Hello-Worldクラスでjavahを実行できます。

  javah -jni HelloWorld

ヘッダーファイルの名前は、末尾に「.h」が追加されたクラス名です。上記のコマンドは、HelloWorld.hという名前のファイルを生成します。ここでは、生成されたヘッダーファイル全体をリストしません。ヘッダーファイルの最も重要な部分は、Java_HelloWorld_printの関数プロトタイプです。これは、HelloWorld.printメソッドを実装するC関数です。

 JNIEXPORT void JNICALL   Java_HelloWorld_print (JNIEnv *, jobject);

現時点では、JNIEXPORTおよびJNICALLマクロは無視してください。ネイティブメソッドのC実装は、ネイティブメソッドの対応する宣言が引数を受け入れない場合でも、2つの引数を受け入れることに気づいたかもしれません。すべてのネイティブメソッド実装の最初の引数は、JNIEnvインターフェイスポインターです。 2番目の引数は、HelloWorldオブジェクト自体への参照です(C++の「this」ポインターのようなもの)。この本の後半でJNIEnvインターフェイスポインターとjobject引数の使用方法について説明しますが、この単純な例では両方の引数を無視します。

2.5ネイティブメソッド実装の記述

javahによって生成されたJNIスタイルのヘッダーファイルは、ネイティブメソッドのCまたはC++実装を記述するのに役立ちます。作成する関数は、生成されたヘッダーファイルで指定された-prototypeに従う必要があります。次のように、CファイルHello-World.printHelloWorld.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プログラムには3つのヘッダーファイルが含まれています。

jni.h-このヘッダーファイルは、ネイティブコードがJNI関数を呼び出すために必要な情報を提供します。ネイティブメソッドを記述するときは、このファイルをCまたはC++ソースファイルに常に含める必要があります。 stdio.h-上記のコードスニペットには、printf関数を使用するため、stdio.hも含まれています。 HelloWorld.h-javahを使用して生成したヘッダーファイル。 Java_HelloWorld_print関数のC/C++プロトタイプが含まれています。 2.6 Cソースのコンパイルとネイティブライブラリの作成

HelloWorld.JavaファイルにHelloWorldクラスを作成したときに、プログラムにネイティブライブラリをロードするコード行を含めたことを思い出してください。

 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コンパイラに指示します。この本ではページ幅の制限のため、コマンドラインを2行に分けています。コマンドを1行で入力するか、コマンドをスクリプトファイルに配置する必要があります。 Win32で、次のコマンドはMicrosoft Visual C++コンパイラーを使用してダイナミックリンクライブラリ(DLL)HelloWorld.dllを構築します。

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

-MDオプションは、HelloWorld.dllWin32マルチスレッドCライブラリとリンクされるようにします。 -LDオプションは、通常のWin32実行可能ファイルの代わりにDLLを生成するようにCコンパイラに指示します。もちろん、SolarisとWin32の両方で、独自のセットアップを反映するインクルードパスに入れる必要があります機械。

2.7プログラムを実行する

この時点で、プログラムを実行する準備ができている2つのコンポーネントがあります。クラスファイル(HelloWorld.class)はネイティブメソッドを呼び出し、ネイティブライブラリ(Hello-World.dll)はネイティブメソッドを実装します。

HelloWorldクラスには独自のmainメソッドが含まれているため、SolarisまたはWin32で次のようにプログラムを実行できます。

 Java HelloWorld

次の出力が表示されます。

   Hello World! 

プログラムを実行するには、ネイティブライブラリパスを正しく設定することが重要です。ネイティブライブラリパスは、ネイティブライブラリをロードするときにJava仮想マシンが検索するディレクトリのリストです。正しく設定されたネイティブライブラリパスがない場合、次のようなエラーが表示されます。以下:

 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) 

ネイティブライブラリが、ネイティブライブラリパスのいずれかのディレクトリにあることを確認してください。 Solarisシステムで実行している場合、LD_LIBRARY_PATH環境変数を使用してネイティブライブラリパスを定義します。 libHelloWorld.soファイルを含むディレクトリの名前が含まれていることを確認してください。 libHelloWorld.soファイルが現在のディレクトリにある場合、標準のシェル(sh)またはKornShell(ksh)で次の2つのコマンドを発行して、LD_LIBRARY_PATH環境変数を適切に設定できます。

 LD_LIBRARY_PATH=.
 export LD_LIBRARY_PATH

Cシェルの同等のコマンド(cshまたはtcsh)は次のとおりです。

 setenv LD_LIBRARY_PATH .

Windows 95またはWindows NTマシンで実行している場合は、HelloWorld.dllが現在のディレクトリ、またはPATH環境変数にリストされているディレクトリにあることを確認してください。

Java 2 SDK 1.2リリースでは、次のようにシステムプロパティとしてJavaコマンドラインでネイティブライブラリパスを指定することもできます。

 Java -Djava.library.path=. HelloWorld

-D」コマンドラインオプションは、Javaプラットフォームシステムプロパティ。Java.library.pathプロパティを「.」に設定すると、Java現在のディレクトリ内のライブラリ。

72
Jonas

簡単に言えば、関数定義を含む関連ライブラリをロードし、JNI仕様に従って最初のライブラリからターゲット関数をラップするライブラリをロードし、Java =クラスとあなたは行くのが良いはずです。

多くの定型コードが含まれており、bigCライブラリのラッピングを開始すると、呪われてしまうため、生のJNIにはお勧めしません。開始するときはJNIに手を出してみてください。ただし、実際の作業では [〜#〜] jna [〜#〜] のようなものを使用してください。

11

次のオプションがあります。

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

見積もり:

JNIを使​​用すると、プログラマはネイティブメソッドを記述して、アプリケーションをJavaプログラミング言語で完全に記述できない場合、たとえば、標準Javaプラットフォーム固有の機能またはプログラムライブラリをサポートする

Java Native Access

参照: https://en.wikipedia.org/wiki/Java_Native_Access

見積もり:

Java Native Accessは、JavaプログラムがJava Native Interfaceを使用せずに、ネイティブ共有ライブラリに簡単にアクセスできるようにするコミュニティ開発のライブラリです。

JNR-FFI

参照: https://github.com/jnr/jnr-ffi

見積もり:

jnr-ffiは、手動でJNIコードを記述したり、SWIGなどのツールを使用したりせずにネイティブライブラリをロードするためのJavaライブラリです。

5
Dawnkeeper

「エキゾチック」カテゴリで、NestedVMを参照してください。NestedVMは、CをMipsにコンパイルし、JVM内でMips VMを実行します。

http://nestedvm.ibex.org/

2
ddyer

WindowsおよびMinGW gccを使用している場合、libの特定のメソッドに対してUnsatisfiedLinkErrorを取得している場合、追加のフラグが必要になる場合があります。

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

JNAeratorをチェックアウトします。 https://code.google.com/p/jnaerator/

ソースコードやプリプロセッサの定義などを提供する必要があります。

1
Aykut Kllic

この問題の解決策を得ました。確認する必要があるのは、64ビットJREで実行するJava関数を呼び出すために64ビットc ++コンパイラを使用してコードをコンパイルしていることです。それに加えて、作成されたdllのパスを保存する必要があります「環境変数」の下の「パス」にあるファイル。

0
Dila Gurung

最初に、プロパティ_Java.library.path_でパスを設定して、クラスパスにネイティブライブラリまたは.dllファイルを必ずロードしてください。

次にSystem.loadLibrary()を使用します

_Do not use .dll extension at the end.
_
0
user3906011

@ Jonas は非常に詳細な回答を提供しましたが、このWebサイトを確認する価値もあると思います。

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

JNIを使​​用してプログラムを呼び出す方法を説明します。

  • 言語CおよびC++、または両方の混合物の場合
  • パラメーター、プリミティブ、ストリング、またはプリミティブの配列のないJNI
  • オブジェクト変数、コールバックインスタンスメソッドなどにアクセスします。
0
aks

64ビット互換のdllを作成するには、以下のステートメントから「-MD」オプションを削除します

「cl -Ic:\ Java\include -Ic:\ Java\include\win32 -MD -LD HelloWorld.c -FeHelloWorld.dll」

0
Dila Gurung

[〜#〜] jni [〜#〜] -Javaネイティブインターフェイス

JavaからC関数を呼び出すには、 [〜#〜] jni [〜#〜] を使用する必要があります。

0
Steven Bialecki