Javaからc関数を呼び出す方法。 cはコンパイラベースのようです。
JavaからWindowsのC関数を呼び出し、GCC関数fron Javaも。
参照はありますか?
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.print
で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プログラムには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.dll
がWin32
マルチスレッド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現在のディレクトリ内のライブラリ。
簡単に言えば、関数定義を含む関連ライブラリをロードし、JNI仕様に従って最初のライブラリからターゲット関数をラップするライブラリをロードし、Java =クラスとあなたは行くのが良いはずです。
多くの定型コードが含まれており、bigCライブラリのラッピングを開始すると、呪われてしまうため、生のJNIにはお勧めしません。開始するときはJNIに手を出してみてください。ただし、実際の作業では [〜#〜] jna [〜#〜] のようなものを使用してください。
次のオプションがあります。
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ライブラリです。
「エキゾチック」カテゴリで、NestedVMを参照してください。NestedVMは、CをMipsにコンパイルし、JVM内でMips VMを実行します。
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
JNAeratorをチェックアウトします。 https://code.google.com/p/jnaerator/
ソースコードやプリプロセッサの定義などを提供する必要があります。
この問題の解決策を得ました。確認する必要があるのは、64ビットJREで実行するJava関数を呼び出すために64ビットc ++コンパイラを使用してコードをコンパイルしていることです。それに加えて、作成されたdllのパスを保存する必要があります「環境変数」の下の「パス」にあるファイル。
最初に、プロパティ_Java.library.path
_でパスを設定して、クラスパスにネイティブライブラリまたは.dllファイルを必ずロードしてください。
次にSystem.loadLibrary()
を使用します
_Do not use .dll extension at the end.
_
@ Jonas は非常に詳細な回答を提供しましたが、このWebサイトを確認する価値もあると思います。
http://www.ntu.edu.sg/home/ehchua/programming/Java/javanativeinterface.html
JNIを使用してプログラムを呼び出す方法を説明します。
64ビット互換のdllを作成するには、以下のステートメントから「-MD」オプションを削除します
「cl -Ic:\ Java\include -Ic:\ Java\include\win32 -MD -LD HelloWorld.c -FeHelloWorld.dll」
[〜#〜] jni [〜#〜] -Javaネイティブインターフェイス
JavaからC関数を呼び出すには、 [〜#〜] jni [〜#〜] を使用する必要があります。