JNI 実行時リンク
Java™ Native Interface (JNI) を使用すると、動的ネイティブ・ライブラリーおよび静的ネイティブ・ライブラリーへのランタイム・リンクが可能になります。
AIX システムに固有の情報
ランタイム・リンクの場合、-brtlローダー・オプションを使用してアプリケーションをリンクできます。 実行時リンクによって記号の競合が起こる場合、アプリケーションは、アプリケーション側で記号の名前を変更するか、実行時リンクをオフにすることで、競合を解決する必要があります。
AIX でのダイナミック・リンク
cc_r -qmkshrobj [-qarch=ppc | -q64] -Ijava_install_dir/include
-o libnm.a nm.c-qmkshrobjオプションは、ランタイム・リンクを使用不可にします。 共有オブジェクト・ファイル、ランタイム・リンク、およびccコマンド行オプションとldコマンド行オプションの使用について詳しくは、以下を参照してください。- Developing and Porting C and C++ Applications on AIX ( http://www.redbooks.ibm.com/abstracts/sg245674.html)
- C および C++ コンパイラーの Web サイト ( https://www.ibm.com/marketplace/ibm-c-and-c-plus-plus-compiler-family )
- AIX オンライン資料 ( https://www.ibm.com/support/knowledgecenter/ssw_aix/welcome )
ネイティブ・メソッドを使用する Java プログラムを実行する前に、ネイティブ・メソッドの共有オブジェクトを保持するディレクトリーのリストが LIBPATH に含まれていることを確認してください。 AIX 共有オブジェクトの作成について詳しくは、 AIX を参照してください。 https://www.ibm.com/redbooks にアクセスして、「SG245674」を検索してください。
JNIネイティブ・コード・プログラムでセットアップID 属性またはセットID属性を設定すると、その設定によって有効なLIBPATH環境変数が変更されます。 この変更のために、それらのプログラムで予期しない動作または正しくない動作が行われる場合があります。 この使用法について詳しくは、「 Developing and Porting C and C++ Applications on AIX 」( http://www.redbooks.ibm.com/abstracts/sg245674.htmlのセクション 2.3.3) を参照してください。
JNI 呼び出し API を使用して Java 仮想マシンを作成し、Java コードを呼び出す C または C++ プログラムをビルドする場合は、 -L オプションを使用して以下のタスクを実行します。
- /usr/libおよび/libを、共有オブジェクトを検索するディレクトリーのリストに追加します。 これらのディレクトリーに保管されている共有オブジェクトは、すべてのプログラムが必要とします。
- Java java_install_dir/jre/lib および java_install_dir/jre/lib/j9vm ディレクトリーを、共有オブジェクトを検索するディレクトリーのリストに追加します。 これらのディレクトリーには、Java 共有ライブラリーが含まれています。 libjvm.so とのリンク (-ljvm オプションを使用) も必要です。
例えば、以下のコードは、JNI呼び出しAPIを使用するCプログラム(invAPITest.c)をビルドします。
cc_r [-qarch=pwr4 | -q64] -Ijava_install_dir/include
-o invAPITest
-L/usr/lib
-L/lib
-Ljava_install_dir/jre/lib/j9vm
-Ljava_install_dir/jre/lib
-ljvm invAPITest.c
JNI 呼び出し API を使用して Java クラスを実行する C または C++ プログラムを実行する場合は、JVM がクラス・ファイルを検出できるようにクラスパスが正しくセットアップされていることを確認してください。 Java ブート・クラスパスを変更する場合は、アプリケーションの実行に必要な SDK ファイルを含めてください。
JNI呼び出しAPIを使用しているCまたはC++プログラムが-bM:URオプションでビルドされたものかどうかを判断するには、次のコマンドを使用します。
dump [-X64] -ov <program name>
以下のような出力が生成されます。
>dump -X64 -ov <program name>
***Object Module Header***
# Sections Symbol Ptr # Symbols Opt Hdr Len Flags
4 0x0001a728 1305 120 0x1002
Flags=( EXEC DYNLOAD DEP_SYSTEM )
Timestamp = "14 Oct 03:26:43 2005"
Magic = 0x1f7 (64-bit XCOFF)
***Optional Header***
Tsize Dsize Bsize Tstart Dstart
0x000127f8 0x00001b80 0x00000470 0x1000001f8 0x1100009f0
SNloader SNentry SNtext SNtoc SNdata
0x0004 0x0002 0x0001 0x0002 0x0002
TXTalign DATAalign TOC vstamp entry
0x0005 0x0003 0x110002158 0x0001 0x110002040
maxSTACK maxDATA SNbss magic modtype
0x00000000 0x00000000 0x0003 0x010b UR
-bM:UR バインダー・オプションを指定してコンパイルされたかのようにプログラムを動作させることができます。 例:export LDR_CNTRL=USERREGS
LDR_CNTRLで複数のオプションを指定する必要がある場合は、それらのオプションを@記号で区切ります。
export AIXTHREAD_SCOPE=S
もう 1 つのオプションは、スレッドの作成時に AIX pthread_attr_setscope 関数を使用して、スレッドのスコープ属性を PTHREAD_SCOPE_SYSTEM に事前設定することです。
- 共有オブジェクト
- 共有オブジェクトは、 XCOFF ヘッダーで SRE (共有再使用可能) ビットを設定した単一のオブジェクト・ファイルです。 SRE ビットは、このファイルが動的にリンクされることをリンカーに通知します。 これらのファイルは通常、<filename> .oという形式の名前になりますが、リンカーが-lnameオプションを使用して検索できるようにlib<name> .aという名前にすることもできます。ただし、これらはアーカイブ・ライブラリー・ファイルではありません。
- 共有ライブラリー
- 共有ライブラリーは、 1 つ以上のアーカイブ・メンバーがその中の共有オブジェクトである「ar」形式のアーカイブ・ライブラリーです。 このライブラリーには、静的にリンクされた非共有オブジェクト・ファイルも含まれることに注意してください。 共有ライブラリーの名前はlib<name> .aの形式です。 このフォームにより、リンカーは-lnameオプションを使用してライブラリーを検索できます。
詳しくは、 AIX の資料を参照してください。
プログラムは、サブルーチンの dlopen() ファミリーを使用するなどして、共有ライブラリーおよび共有オブジェクトに動的にリンクすることもできます。 JVM は、ネイティブ・ライブラリー (例えば、System.load()、 System.loadLibrary()、 Runtime.getRuntime().load()、 Runtime.getRuntime().loadLibrary()) をロードするときにこの方法でリンクします。
dlopen については、 dlopen サブルーチンを参照してください。
AIX のロードとリンクのメカニズムについては、「 AIX リンクとロードのメカニズム」を参照してください。
System.loadLibrary("<library>(<member>)")ここで、<library> は共有ライブラリー・アーカイブの名前、<member> はアーカイブ・メンバーの名前です。 例:System.loadLibrary("libShared.a(libSample.o)")
AIX での静的リンク
JNI ライブラリーは、動的にリンクするのに加え、静的にもリンクできます。 静的ライブラリーは、呼び出し API を使用して JVM プロセスを起動するカスタム・ランチャーのイメージに、組み合わせることができます。
testlibA および testlibB の 2 つの静的ライブラリーを考えてみます。 testlibA ライブラリをJavaプログラムにロードしようとして、 System.loadLibrary("testlibA") のようなコマンドを使用した場合、JVMはまず、起動する実行プログラムのイメージから JNI_OnLoad_testlibA( という名前のルーチンを探します。このルーチンが見つかると、JVMは静的にバインドされたライブラリを使用してJNI定義を提供します。 ルーチンが見つからないと、JVM は、-Djava.library.path (または LIBPATH) によって指定されたパスで探すことにより、testlibA ライブラリーを動的にロード (libtestlibA.so など) するためにフォールバックします。
AIXでは、 -brtlを指定してランタイム・リンクを使用可能にするほかに、オプション -bexpall を指定してビルドする必要があります。 このプロセスによりランチャーは、シンボル (JNI_OnLoad_testlibA() など) をエクスポートするのに加え、実行可能プログラム (JVM の実行可能プログラムなど) によってロードされた共有ライブラリーでシンボルを検索できるようにします。 JVM で静的にリンクを行う場合、JVM は、動的リンクで試行する前に実行可能プログラムを検索できなければなりません。
$ cc_r -qpic -brtl -bexpall -brtl testlibA.o testlibB.o -o <launcher>ここで、 < launcher> は、 testlibA ライブラリーと testlibB ライブラリーのイメージ、および呼び出し API を介して JVM を起動する Java ランチャーを含む実行可能プログラムの名前です。ライブラリLのライブラリ初期化ルーチン JNI_OnLoad_L, は、戻り値を返さなければなりませんJNI_VERSION_1_8(0x00010008).
Linux システムに固有の情報
実行時リンクによって記号の競合が起こる場合、アプリケーションは、アプリケーション側で記号の名前を変更するか、実行時リンクをオフにすることで、競合を解決する必要があります。
Linux でのダイナミック・リンク
JNI 呼び出し API を使用して Java 仮想マシンを作成し、Java コードを呼び出す C または C++ プログラムをビルドする場合は、 -L オプションを使用して以下のタスクを実行します。
- /usr/libおよび/libを、共有オブジェクトを検索するディレクトリーのリストに追加します。 これらのディレクトリーに保管されている共有オブジェクトは、すべてのプログラムが必要とします。
- Java java_install_dir/jre/lib および java_install_dir/jre/lib/j9vm ディレクトリーを、共有オブジェクトを検索するディレクトリーのリストに追加します。 これらのディレクトリーには、Java 共有ライブラリーが含まれています。 libjvm.so とのリンク (-ljvm オプションを使用) も必要です。
例えば、以下のコードは、JNI呼び出しAPIを使用するCプログラム(invAPITest.c)をビルドします。
cc [-m32|-m64] -Ijava_install_dir/include
-o invAPITest
-L/usr/lib
-L/lib
-Ljava_install_dir/jre/lib/j9vm
-Ljava_install_dir/jre/lib
-ljvm invAPITest.c
JNI 呼び出し API を使用して Java クラスを実行する C または C++ プログラムを実行する場合は、JVM がクラス・ファイルを検出できるようにクラスパスが正しくセットアップされていることを確認してください。 Java ブート・クラスパスを変更する場合は、アプリケーションの実行に必要な SDK ファイルを含めてください。
実行時に Java アプリケーションが解決する必要がある関数を JNI ライブラリーがエクスポートするようにするには、 nm ツールを使用してライブラリーを調べることができます。 例えば、JNI ルーチン fooImpl および barImpl を含む libjnitest.so という名前の JNI ライブラリーは、以下のシンボルをエクスポートする必要があります。
$ nm libjnitest.so
000537d0 T Java_mypackage_SampleClass_fooImpl
0004f020 T Java_mypackage_SampleClass_barImpl
同様に、コマンド objdump -T では、以下に示す、共有ライブラリー内のエクスポートされるシンボルをリストします。
000537d0 g DF .text 00000040 Base 0x60
Java_mypackage_SampleClass_fooImpl
0004f020 g DF .text 00000254 Base 0x60
Java_mypackage_SampleClass_barImpl
- 共有ライブラリー
- Linux 上の共有ライブラリー (または共有オブジェクト) は、ビルド時 (リンク時リンク) または実行時 (実行時リンク) にリンクできるダイナミック・リンク・ライブラリーです。 共有ライブラリーへのリンク時リンクはリンカー・エディター・ツール ld を使用して行うのに対し、実行時リンクでは関数の dlopen(3) ファミリーを使用します。
プログラムは、サブルーチンの dlopen() ファミリーを使用するなどして、共有ライブラリーおよび共有オブジェクトに動的にリンクすることもできます。 JVM は、ネイティブ・ライブラリー (例えば、System.load()、 System.loadLibrary()、 Runtime.getRuntime().load()、 Runtime.getRuntime().loadLibrary()) をロードするときにこの方法でリンクします。
dlopen(3)については、 Linux のマニュアル資料を参照し、 dlopenを検索してください。
Linux での静的リンク
JNI ライブラリーは、動的にリンクするのに加え、静的にもリンクできます。 静的ライブラリーは、呼び出し API を使用して JVM プロセスを起動するカスタム・ランチャーのイメージに、組み合わせることができます。
testlibA および testlibB の 2 つの静的ライブラリーを考えてみます。 testlibA ライブラリをJavaプログラムにロードしようとして、 System.loadLibrary("testlibA") のようなコマンドを使用した場合、JVMはまず、起動する実行プログラムのイメージから JNI_OnLoad_testlibA( という名前のルーチンを探します。このルーチンが見つかると、JVMは静的にバインドされたライブラリを使用してJNI定義を提供します。 ルーチンが見つからないと、JVM は、-Djava.library.path (または LD_LIBRARY_PATH) によって指定されたパスで探すことにより、testlibA ライブラリーを動的にロード (libtestlibA.so など) するためにフォールバックします。
Linux では、ランチャーがシンボル( JNI_OnLoad_testlibA( など)をエクスポートし、また実行プログラム(JVMなど)によって読み込まれる共有ライブラリがシンボルを検索できるように、 -rdynamic オプションを指定してビルドする必要があります。 JVM で静的にリンクを行う場合、JVM は、動的リンクで試行する前に実行可能プログラムを検索できなければなりません。 -rdynamic を指定しないと、静的でないシンボルは、実行可能プログラムから引き続きエクスポートされますが、実行可能プログラムによりロードされた共有ライブラリーから認識されません。 -rdynamic の使用例は次のとおりです。
$ cc -rdynamic testlibA.o testlibB.o -o <launcher>
ライブラリLのライブラリ初期化ルーチン JNI_OnLoad_L, は、戻り値を返さなければなりませんJNI_VERSION_1_8(0x00010008).
Windows システムに固有の情報
実行時リンクによって記号の競合が起こる場合、アプリケーションは、アプリケーション側で記号の名前を変更するか、実行時リンクをオフにすることで、競合を解決する必要があります。
Windows でのダイナミック・リンク
JNI 呼び出し API を使用して Java 仮想マシンを作成し、Java コードを呼び出す C または C++ プログラムをビルドする場合は、リンカー・オプション /link /LIBPATH を使用して以下のタスクを実行します。
- Java java_install_dir\jre\bin\ および java_install_dir\jre\bin\j9vm ディレクトリーを、共有オブジェクトを検索するディレクトリーのリストに追加します。 これらのディレクトリーには、Java 共有ライブラリーが含まれています。 jvm.dll とのリンク (-ljvm オプションを使用) も必要です。
Windows では、コマンド行コンパイラー cl.exeに特別なオプションは必要ありません。 通常、Microsoft コンパイラー (VC + + など) が使用されます。コンパイラー・オプションについて詳しくは、使用されているコンパイラーの資料を参照してください。 デフォルトでは、VC++ は、環境変数 %LIB% で示される場所にあるライブラリーを使用します。 この変数は、ライブラリーをリンクするための検索パスの 1 つとして、常に VC++ SDK の \lib サブディレクトリーを指す必要があります。
cl.exe /I java_install_dir\jre\include
/FeinvAPITest
invAPITest.c
/link /LIBPATH:java_install_dir\jre\bin\j9vm
/LIBPATH:java_install_dir\jre\bin
JNI 呼び出し API を使用して Java クラスを実行する C または C++ プログラムを実行する場合は、JVM がクラス・ファイルを検出できるようにクラスパスが正しくセットアップされていることを確認してください。 Java ブート・クラスパスを変更する場合は、アプリケーションの実行に必要な SDK ファイルを含めてください。
C:\>dumpbin.exe /EXPORTS jnitest.dll
Dump of file jnitest.dll
File Type: DLL
Section contains the following exports for JNITEST.dll
00000000 characteristics
5412A472 time date stamp Fri Sep 12 03:44:50 2014
0.00 version
1 ordinal base
5 number of functions
5 number of names
ordinal hint RVA name
...
1 27 0000CE10 Java_mypackage_SampleClass_fooImpl = Java_mypackage_SampleClass_fooImpl
2 28 000085A0 Java_mypackage_SampleClass_barImpl = Java_mypackage_SampleClass_barImpl
...
dumpbin.exeとそのオプションについて詳しくは、MSDNの資料を参照してください。
- ダイナミック・リンク・ライブラリー
- Windows では、JNI メソッドは通常、ダイナミック・リンク・ライブラリー (DLL) と呼ばれる動的ライブラリーに保管されます。 DLL には、別のロード・モジュール (動的ライブラリーや実行可能プログラムなど) から参照できる関数およびデータが含まれています。 ネイティブ・メソッドは DLL に保管され、ビルド時にリンクされるか、リンク・プロセスを介してリンクされるか、または実行時に Windows API LoadLibrary() および LoadLibraryEx() 関数を使用してメソッドを動的にロードすることによってリンクされます。 関数の LoadLibrary() ファミリーについて詳しくは、MSDN の資料を参照してください。
Windows での静的リンク
JNI ライブラリーは、動的にリンクするのに加え、静的にもリンクできます。 静的ライブラリーは、呼び出し API を使用して JVM プロセスを起動するカスタム・ランチャーのイメージに、組み合わせることができます。
testlibA および testlibB の 2 つの静的ライブラリーを考えてみます。 testlibA ライブラリをJavaプログラムにロードしようとして、 System.loadLibrary("testlibA") のようなコマンドを使用した場合、JVMはまず、起動する実行プログラムのイメージから JNI_OnLoad_testlibA( という名前のルーチンを探します。このルーチンが見つかると、JVMは静的にバインドされたライブラリを使用してJNI定義を提供します。 ルーチンが見つからないと、JVM は、-Djava.library.path (または PATH) によって指定されたパスで探すことにより、testlibA ライブラリーを動的にロード (testlibA.dll など) するためにフォールバックします。
Windows では、ランチャー実行可能プログラムのビルド中に指定する特別なオプションはありません。
ライブラリLのライブラリ初期化ルーチン JNI_OnLoad_L, は、戻り値を返さなければなりませんJNI_VERSION_1_8(0x00010008).
z/OS システムに固有の情報
実行時リンクによって記号の競合が起こる場合、アプリケーションは、アプリケーション側で記号の名前を変更するか、実行時リンクをオフにすることで、競合を解決する必要があります。
z/OS でのダイナミック・リンク
JNI 呼び出し API を使用して Java 仮想マシンを作成し、Java コードを呼び出す C または C++ プログラムをビルドする場合は、 -L オプションを使用して以下のタスクを実行します。
- /usr/libおよび/libを、共有オブジェクトを検索するディレクトリーのリストに追加します。 これらのディレクトリーに保管されている共有オブジェクトは、すべてのプログラムが必要とします。
- Java java_install_dir/jre/lib および java_install_dir/jre/lib/j9vm ディレクトリーを、共有オブジェクトを検索するディレクトリーのリストに追加します。 これらのディレクトリーには、Java 共有ライブラリーが含まれています。 libjvm.so とのリンク (-ljvm オプションを使用) も必要です。
例えば、次のコードは、CプログラムinvAPITest.cをコンパイルして、invAPITestという名前の呼び出し API ランチャーを作成します。
cc [-q32|-q64] -Ijava_install_dir/jre/include
-o invAPITest
-L/usr/lib
-L/lib
-Ljava_install_dir/jre/lib/j9vm
-Ljava_install_dir/jre/lib
-ljvm invAPITest.c
値-q32または-q64は、プログラムが作成されるデータ・モデルを指定します。 これらの値を省略すると、デフォルトのデータ・モデルが使用されます。
JNI 呼び出し API を使用して Java クラスを実行する C または C++ プログラムを実行する場合は、JVM がクラス・ファイルを検出できるようにクラスパスが正しくセットアップされていることを確認してください。 Java ブート・クラスパスを変更する場合は、アプリケーションの実行に必要な SDK ファイルを含めてください。
実行時に Java アプリケーションが解決する必要がある関数を JNI ライブラリーがエクスポートするようにするには、 nm ツールを使用してライブラリーを調べることができます。 例えば、名前が libjnitest.so で、JNI ルーチン fooImpl および barImpl を含む JNI ライブラリーでは、以下のシンボルをエクスポートする必要があります。
$nm libjnitest.so
255552 T Java_mypackage_SampleClass_fooImpl
255528 T Java_mypackage_SampleClass_barImpl
詳しくは、 コンパイラー・オプションのデフォルトを参照してください。
- ダイナミック・リンク・ライブラリー
- IBM Z® システムでは、JNI メソッドは通常、ダイナミック・リンク・ライブラリー (DLL) と呼ばれる動的ライブラリーに保管されます。 DLL には、別のロード・モジュール (動的ライブラリーや実行可能プログラムなど) から参照できる関数およびデータが含まれています。 ネイティブ・メソッドは DLL に保管され、リンク・プロセスを介してビルド時にリンクされるか、実行時に IBM Z API dllload または POSIX準拠 API dlopenを使用してメソッドを動的にロードすることによってリンクされます。 dllload () 関数および dlopen () 関数について詳しくは、「 DLL のロード」を参照してください。
プログラムは、サブルーチンの dlopen() ファミリーまたは dllload() ファミリーを使用するなどして、共有ライブラリーおよび共有オブジェクトに動的にリンクすることもできます。 JVM は、ネイティブ・ライブラリー (例えば、System.load()、 System.loadLibrary()、 Runtime.getRuntime().load()、 Runtime.getRuntime().loadLibrary()) をロードするときにこの方法でリンクします。
これらのサブルーチンについては、 dlopen () および dllload ()を参照してください。
z/OS での静的リンク
JNI ライブラリーは、動的にリンクするのに加え、静的にもリンクできます。 静的ライブラリーは、呼び出し API を使用して JVM プロセスを起動するカスタム・ランチャーのイメージに、組み合わせることができます。
testlibA および testlibB の 2 つの静的ライブラリーを考えてみます。 testlibA ライブラリをJavaプログラムにロードしようとして、 System.loadLibrary("testlibA") のようなコマンドを使用した場合、JVMはまず、起動する実行プログラムのイメージから JNI_OnLoad_testlibA( という名前のルーチンを探します。このルーチンが見つかると、JVMは静的にバインドされたライブラリを使用してJNI定義を提供します。 ルーチンが見つからないと、JVM は、-Djava.library.path (または LIBPATH) によって指定されたパスで探すことにより、testlibA ライブラリーを動的にロード (libtestlibA.so など) するためにフォールバックします。
- 実行プログラムがDLLとしてビルドされることを確認するための
Wc,DLL - 実行プログラムのシンボルがエクスポートされ、プログラムがロードする共有ライブラリから参照できるようにするための
Wc,EXPORTALL
cc -c -Wc,DLL,EXPORTALL launcher.c -o launcher.o
cc testlibA.o testlibB.o launcher.o -o launcher
また、EXPORTALLを削除すると、#pragma exportを使用して特定のシンボルをエクスポートすることができます。 詳しくは、 #pragma エクスポートを参照してください。
ライブラリLのライブラリ初期化ルーチン JNI_OnLoad_L, は、戻り値を返さなければなりませんJNI_VERSION_1_8(0x00010008).