JNI runtime linking

The Java™ Native Interface (JNI) enables runtime linking to dynamic and static native libraries.

See the following sections for platform-specific information:

Information specific to AIX systems

For runtime linking, applications can be linked by using the  -brtl loader option. If runtime linking causes a symbol conflict, the application must resolve the conflict by renaming the symbol on the application side, or by turning off runtime linking.

Dynamic linking in AIX

To dynamically link a native library, you should compile your native methods (C or C++ functions called by Java) into AIX shared objects (dynamically loaded libraries). For example, if your native methods are stored in the file nm.c, you could create the shared object with the following command:
cc_r -qmkshrobj [-qarch=ppc | -q64] -Ijava_install_dir/include 
-o libnm.a nm.c
The -qmkshrobj option disables runtime linking. For more information about shared object files, runtime linking, and the use of cc and ld command-line options, see:

Before you run a Java program that uses native methods, ensure that LIBPATH contains the list of directories that hold the shared objects for the native methods. For more information about building AIX shared objects, see C and C++ Application Development on AIX . Go to https://www.ibm.com/redbooks and search for "SG245674".

If you set the setuid or setgid attribute on JNI native code programs, that setting changes the effective LIBPATH environment variable. This change might cause unexpected or incorrect behavior with those programs. For more information about this usage, see Developing and Porting C and C++ Applications on AIX at http://www.redbooks.ibm.com/abstracts/sg245674.html, section 2.3.3.

When you build a C or C++ program that uses the JNI Invocation API to create a Java virtual machine, and calls Java code, use the -L option to do the following tasks:

  • Add /usr/lib and /lib to the list of directories that are searched for shared objects. All programs need shared objects that are stored in these directories.
  • Add your Java java_install_dir/jre/lib and java_install_dir/jre/lib/j9vm directories to the list of directories that are searched for shared objects. These directories contain the Java shared libraries. You also want to link with libjvm.so (by using the -ljvm option).

For example, this code builds a C program (invAPITest.c) that uses the JNI Invocation API:

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

When you run a C or C++ program that uses the JNI Invocation API to run Java classes, ensure that the class path is set up correctly to enable the JVM to find your class files. If you modify the Java boot class path, include the SDK files that are necessary to run your applications.

To determine whether a C or C++ program that is using the JNI Invocation API was built with the -bM:UR option, use the following command:

dump [-X64] -ov <program name> 

Output similar to the following is generated:

>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
If the modtype is not UR, you can use the LDR_CNTRL environment variable to make programs behave as though they were compiled with the -bM:UR binder option. For example:
export LDR_CNTRL=USERREGS

If you need to specify multiple options with LDR_CNTRL, separate those options with the @ symbol.

Java threads that are created by the JVM use the POSIX pthreads model that is supported on AIX. Currently, this approach is on a 1-to-1 mapping with the kernel threads. When you develop a JNI program, you must run with a 1-to-1 thread model and system contention scope if you create pthreads in your own program. You can control this behavior by using the following environment setting:
export AIXTHREAD_SCOPE=S

Another option is to preset the thread's scope attribute to PTHREAD_SCOPE_SYSTEM by using the AIX pthread_attr_setscope function when the thread is created.

You can store native methods as follows:
Shared object
A shared object is a single object file that has the SRE (Shared REusable) bit set in the XCOFF header. The SRE bit tells the linker that this file is linked dynamically. These files typically have a name of the form <filename> .o, but they can also be named lib<name> .a to allow the linker to search for them with the -lname option; but these are not archive library files.
Shared library
A shared library is an "ar" format archive library in which one or more of the archive members is a shared object. Note that this library can also contain non-shared object files that are statically linked. A shared library has the name in the form lib<name> .a. This form allows the linker to search for libraries with the -lname option.

For more information, see the AIX documentation.

Programs can also link dynamically to shared libraries and shared objects, for example by using the dlopen() family of subroutines. The JVM links in this way when it loads native libraries (for example, System.load(), System.loadLibrary(), Runtime.getRuntime().load(), Runtime.getRuntime().loadLibrary()).

For information about dlopen see dlopen Subroutine.

For information about AIX loading and linking mechanisms, see AIX Linking and Loading Mechanisms.

To load an AIX shared library, make a call to:
System.loadLibrary("<library>(<member>)")
where <library> is the name of the shared library archive and <member> is the name of an archive member. For example:
System.loadLibrary("libShared.a(libSample.o)")
Note: To ensure that dynamic linking of native libraries works successfully you can, optionally, implement the lifecycle functions JNI_Onload() and JNI_OnUnload() in the library. If you have implemented JNI_Onload(), the native library must export it otherwise it is not visible to the runtime, and the JVM assumes that the library requires only the JNI version JNI_VERSION_1.1. If JNI_OnUnload() has been implemented, it must also be exported. If JNI_Onload() is implemented and exported, then the latest JNI version is returned; for example, JNI_VERSION_1.8.

Static linking in AIX

You can link to JNI libraries statically, in addition to linking dynamically. Static libraries can be combined into the image of a custom launcher that launches a JVM process by using the invocation APIs.

Consider two static libraries: testlibA and testlibB. If you attempt to load the testlibA library in the Java program by using a command such as System.loadLibrary("testlibA"), the JVM first looks into the launching executable program's image for a routine named JNI_OnLoad_testlibA(). If this routine is found, the JVM uses this statically bound library to provide JNI definitions. If the routine is not found, the JVM falls back to load the testlibA library dynamically (for example libtestlibA.so) by looking in paths that are specified by -Djava.library.path (or LIBPATH).

On AIX, in addition to enabling the runtime linking by specifying -brtl, you must build with the option -bexpall specified. This process ensures that the launcher exports symbols (such as JNI_OnLoad_testlibA()) and also allows shared libraries that are loaded by the executable program (such as that of the JVM) to look up the symbols. For the JVM to statically link, it must be able to look back into the executable program before any attempt at dynamic linking.

You can also build an executable program with static libraries, by using the following command:
$ cc_r -qpic -brtl -bexpall -brtl testlibA.o testlibB.o -o <launcher>
where <launcher> is the name of an executable program that contains the images of the testlibA and testlibB libraries, as well as being a Java launcher that launches a JVM through the invocation APIs.

The library initialization routine JNI_OnLoad_L, for a library L, must return JNI_VERSION_1_8(0x00010008).

Information specific to Linux systems

If runtime linking causes a symbol conflict, the application must resolve the conflict by renaming the symbol on the application side, or by turning off runtime linking.

Dynamic linking in Linux

When you build a C or C++ program that uses the JNI Invocation API to create a Java virtual machine, and calls Java code, use the -L option to do the following tasks:

  • Add /usr/lib and /lib to the list of directories that are searched for shared objects. All programs need shared objects that are stored in these directories.
  • Add your Java java_install_dir/jre/lib and java_install_dir/jre/lib/j9vm directories to the list of directories that are searched for shared objects. These directories contain the Java shared libraries. You also want to link with libjvm.so (by using the -ljvm option).

For example, this code builds a C program (invAPITest.c) that uses the JNI Invocation API:

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

When you run a C or C++ program that uses the JNI Invocation API to run Java classes, ensure that the class path is set up correctly to enable the JVM to find your class files. If you modify the Java boot class path, include the SDK files that are necessary to run your applications.

To ensure that a JNI library exports the functions that a Java application must resolve at runtime, you can examine the library by using the nm tool. For example, a JNI library named libjnitest.so that contains JNI routines fooImpl and barImpl must export the following symbols:

$ nm libjnitest.so
000537d0 T Java_mypackage_SampleClass_fooImpl
0004f020 T Java_mypackage_SampleClass_barImpl

Similarly, the command objdump -T lists the exported symbols in a shared library:

000537d0  g    DF .text  00000040  Base        0x60 
Java_mypackage_SampleClass_fooImpl
0004f020  g    DF .text  00000254  Base        0x60 
Java_mypackage_SampleClass_barImpl
You can store native methods as follows:
Shared library
A shared library (or shared object) on Linux is a dynamically linking library that can be linked against at build time (link-time linking) or at run time (runtime linking). Whereas link-time linking against a shared library is accomplished by using the linker-editor tool ld , runtime linking uses the dlopen(3) family of functions.

Programs can also link dynamically to shared libraries and shared objects, for example by using the dlopen() family of subroutines. The JVM links in this way when it loads native libraries (for example, System.load(), System.loadLibrary(), Runtime.getRuntime().load(), Runtime.getRuntime().loadLibrary()).

For information about dlopen(3), see the Linux man documentation and search for dlopen.

Note: To ensure that dynamic linking of native libraries works successfully you can, optionally, implement the lifecycle functions JNI_Onload() and JNI_OnUnload() in the library. If you have implemented JNI_Onload(), the native library must export it otherwise it is not visible to the runtime, and the JVM assumes that the library requires only the JNI version JNI_VERSION_1.1. If JNI_OnUnload() has been implemented, it must also be exported. If JNI_Onload() is implemented and exported, then the latest JNI version is returned; for example, JNI_VERSION_1.8.

Static linking in Linux

You can link to JNI libraries statically, in addition to linking dynamically. Static libraries can be combined into the image of a custom launcher that launches a JVM process by using the invocation APIs.

Consider two static libraries: testlibA and testlibB. If you attempt to load the testlibA library in the Java program by using a command such as System.loadLibrary("testlibA"), the JVM first looks into the launching executable program's image for a routine named JNI_OnLoad_testlibA(). If this routine is found, the JVM uses this statically bound library to provide JNI definitions. If the routine is not found, the JVM falls back to load the testlibA library dynamically (for example libtestlibA.so) by looking in paths that are specified by -Djava.library.path (or LD_LIBRARY_PATH).

On Linux, you must build with the option -rdynamic specified to ensure that the launcher exports symbols (such as JNI_OnLoad_testlibA()) and also allows shared libraries that are loaded by the executable program (such as that of the JVM) to look up the symbols. For the JVM to statically link, it must be able to look back into the executable program before any attempt at dynamic linking. Without -rdynamic, non-static symbols are still exported from the executable program, but are not visible to shared libraries that are loaded by the program. The following example shows the usage of -rdynamic:

$ cc -rdynamic testlibA.o testlibB.o -o <launcher>

The library initialization routine JNI_OnLoad_L, for a library L, must return JNI_VERSION_1_8(0x00010008).

Information specific to Windows systems

If runtime linking causes a symbol conflict, the application must resolve the conflict by renaming the symbol on the application side, or by turning off runtime linking.

Dynamic linking in Windows

When you build a C or C++ program that uses the JNI Invocation API to create a Java virtual machine, and calls Java code, use the linker option /link /LIBPATH to do the following task:

  • Add your Java java_install_dir\jre\bin\ and java_install_dir\jre\bin\j9vm directories to the list of directories that are searched for shared objects. These directories contain the Java shared libraries. You also want to link with jvm.dll (by using the -ljvm option).

On Windows, no special options are required for the command-line compiler cl.exe. Generally, a Microsoft compiler is used, for example VC++. For more information about compiler options, see the documentation for the compiler that is being used. By default, VC++ picks libraries that are present in the environment variable %LIB%. The variable must always point at the \lib subdirectory of the VC++ SDK as one of the search paths for linking libraries.

Here is a typical command block to build the invocation API test:
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

When you run a C or C++ program that uses the JNI Invocation API to run Java classes, ensure that the class path is set up correctly to enable the JVM to find your class files. If you modify the Java boot class path, include the SDK files that are necessary to run your applications.

To ensure that a JNI library exports the functions that a Java application must resolve at runtime, you can examine the library by using the dumpbin.exe tool (typically a part of the VC++ SDK installation). For example, a JNI library that is named jnitest.dll, and that contains JNI routines fooImpl and barImpl, must export the symbols:
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
...

For more information on dumpbin.exe and its options, see the MSDN documentation.

You can store native methods as follows:
Dynamic link libraries
On Windows, JNI methods are typically stored in dynamic libraries called Dynamic Link Libraries (DLLs). DLLs contain functions and data, which can be referenced from another load module, for example a dynamic library or an executable program. Native methods are stored in DLLs and are either linked at build time, through the linking process, or at runtime, by dynamically loading the methods by using the Windows API LoadLibrary() and LoadLibraryEx() functions. For more information about the LoadLibrary() family of functions, refer to the MSDN documentation.
Note: To ensure that dynamic linking of native libraries works successfully you can, optionally, implement the lifecycle functions JNI_Onload() and JNI_OnUnload() in the library. If you have implemented JNI_Onload(), the native library must export it otherwise it is not visible to the runtime, and the JVM assumes that the library requires only the JNI version JNI_VERSION_1.1. If JNI_OnUnload() has been implemented, it must also be exported. If JNI_Onload() is implemented and exported, then the latest JNI version is returned; for example, JNI_VERSION_1.8.

Static linking in Windows

You can link to JNI libraries statically, in addition to linking dynamically. Static libraries can be combined into the image of a custom launcher that launches a JVM process by using the invocation APIs.

Consider two static libraries: testlibA and testlibB. If you attempt to load the testlibA library in the Java program by using a command such as System.loadLibrary("testlibA"), the JVM first looks into the launching executable program's image for a routine named JNI_OnLoad_testlibA(). If this routine is found, the JVM uses this statically bound library to provide JNI definitions. If the routine is not found, the JVM falls back to load the testlibA library dynamically (for example testlibA.dll) by looking in paths that are specified by -Djava.library.path (or PATH).

Windows does not impose any special options to be specified while you build a launcher executable program.

The library initialization routine JNI_OnLoad_L, for a library L, must return JNI_VERSION_1_8(0x00010008).

Information specific to z/OS systems

If runtime linking causes a symbol conflict, the application must resolve the conflict by renaming the symbol on the application side, or by turning off runtime linking.

Dynamic linking in z/OS

When you build a C or C++ program that uses the JNI Invocation API to create a Java virtual machine, and calls Java code, use the -L option to do the following tasks:

  • Add /usr/lib and /lib to the list of directories that are searched for shared objects. All programs need shared objects that are stored in these directories.
  • Add your Java java_install_dir/jre/lib and java_install_dir/jre/lib/j9vm directories to the list of directories that are searched for shared objects. These directories contain the Java shared libraries. You also want to link with libjvm.so (by using the -ljvm option).

For example, this code builds an invocation API launcher namedinvAPITest by compiling the C program invAPITest.c:

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

The value -q32 or -q64 specify the data model in which the program is built. If you omit these values, the default data model is used.

When you run a C or C++ program that uses the JNI Invocation API to run Java classes, ensure that the class path is set up correctly to enable the JVM to find your class files. If you modify the Java boot class path, include the SDK files that are necessary to run your applications.

To ensure that a JNI library exports the functions that a Java application must resolve at runtime, you can examine the library by using the nm tool. For example, a JNI library that is named libjnitest.so, and that contains JNI routines fooImpl and barImpl, must export the symbols:

$nm libjnitest.so
     255552 T Java_mypackage_SampleClass_fooImpl
     255528 T Java_mypackage_SampleClass_barImpl

For more information, see Compiler option defaults.

You can store native methods as follows:
Dynamic link libraries
On IBM Z® systems, JNI methods are typically stored in dynamic libraries called Dynamic Link Libraries (DLLs). DLLs contain functions and data, which can be referenced from another load module, for example a dynamic library or an executable program. Native methods are stored in DLLs and are either linked at build time, through the linking process, or at runtime, by dynamically loading the methods by using the IBM Z API dllload or the POSIX-compliant API dlopen. For more information about the dllload() and dlopen() functions, see Loading a DLL.

Programs can also link dynamically to shared libraries and shared objects, for example by using the dlopen() or dllload() families of subroutines. The JVM links in this way when it loads native libraries (for example, System.load(), System.loadLibrary(), Runtime.getRuntime().load(), Runtime.getRuntime().loadLibrary()).

For information about these subroutines, see dlopen() and dllload().

Note: To ensure that dynamic linking of native libraries works successfully you can, optionally, implement the lifecycle functions JNI_Onload() and JNI_OnUnload() in the library. If you have implemented JNI_Onload(), the native library must export it otherwise it is not visible to the runtime, and the JVM assumes that the library requires only the JNI version JNI_VERSION_1.1. If JNI_OnUnload() has been implemented, it must also be exported. If JNI_Onload() is implemented and exported, then the latest JNI version is returned; for example, JNI_VERSION_1.8.

Static linking in z/OS

You can link to JNI libraries statically, in addition to linking dynamically. Static libraries can be combined into the image of a custom launcher that launches a JVM process by using the invocation APIs.

Consider two static libraries: testlibA and testlibB. If you attempt to load the testlibA library in the Java program by using a command such as System.loadLibrary("testlibA"), the JVM first looks into the launching executable program's image for a routine named JNI_OnLoad_testlibA(). If this routine is found, the JVM uses this statically bound library to provide JNI definitions. If the routine is not found, the JVM falls back to load the testlibA library dynamically (for example libtestlibA.so) by looking in paths that are specified by -Djava.library.path (or LIBPATH).

On IBM Z systems, you must specify the following options when you build:
  • Wc,DLL, to ensure that the executable program is built as a DLL
  • Wc,EXPORTALL, to ensure that symbols in the executable program are exported and made available for look-up by shared libraries that the program loads
These options enable the launcher executable program to export symbols (such as JNI_Onload_testlibA()) so that the JVM can look them up before attempting dynamic linking.
The following example uses compilation and link lines to ensure that the static libraries testlibA and testlibB are linked with the launcher, which was built as a DLL, and exports all symbols.
cc -c -Wc,DLL,EXPORTALL launcher.c -o launcher.o
cc testlibA.o testlibB.o launcher.o -o launcher

Alternatively, you could remove EXPORTALL, in which case the program exports specific symbols by using #pragma export. For more information, see #pragma export.

Note: On IBM Z systems, an executable program must be built as a Dynamic Link Library (DLL) in addition to export symbols, if an executable program packages JNI routines that the Java program must reference, by using static linking. If an IBM Z executable program defines and exports JNI_OnLoad_testlibA, but is not itself built as a DLL (that is, -Wc,DLL is not specified), static linking is likely to fail, because the runtime is prevented from resolving the symbol back from the executable program.

The library initialization routine JNI_OnLoad_L, for a library L, must return JNI_VERSION_1_8(0x00010008).