Example of using shared libraries on z/OS

This example describes the process of using native shared libraries with a Java™ application on z/OS systems.

About this task

This task demonstrates how to create a Java application that loads and invokes C functions within a native shared library.

Procedure

  1. Create a sample application Sample.java:
    public class Sample {
        /**
         * A static class initialization block that is run when this class
         * is first loaded. Here, try to load the target libSample.so shared library
         * that implements the printFromNative() method declared later.
         */
        static {
            try {
                System.loadLibrary("Sample");
            } catch (Throwable e) {
                throw new RuntimeException(e);
            }
        }
        
        /**
         * Prints a message to STDOUT.
         * The 'native' keyword indicates that this method is implemented in native code,
         * callable through the Java Native Interface (JNI).
         */
        public static native void printFromNative();
    
        public static void main(String[] args) {
            // Invoke the native method
            Sample.printFromNative();
        }
    }

    This Java application declares a static native method Sample.printFromNative(), and calls this native method from the main method.

    During the static class initialization block that is run when the Sample class is first loaded, the System.loadLibrary("Sample") call loads the target native library libSample.so.
    Note: The System.loadLibrary(libname) API adds the prefix lib and the suffix .so to the library name that you provide. The SDK searches for the target shared library within the library path that is specified in the LIBPATH environment variable. If your target native shared library is an MVS data set, or you have a specific absolute path or library name, use the System.load(filename) API instead.
  2. The Java portion of the application is complete, so you can now compile it:
    javac Sample.java
  3. Use the javac -h command to create a header file for the native code:
    javac -h . Sample.java
    This command generates a C header file that is called Sample.h, with the appropriate JNI method signatures for your native application implementation.
  4. Create a file called Sample.c:
    #include <stdio.h>
    #include "Sample.h"
    
    JNIEXPORT void JNICALL Java_Sample_printFromNative(JNIEnv * env, jclass cls) {
      printf( "Printing from native\n" );
    }
    This file provides the C native implementation of the Java Sample.printFromNative() method.
  5. Compile Sample.c, link, and bind it into a shared library libSample.so, that can be loaded and called dynamically from a Java application. You can use either XL C/C++ or Open XL C/C++ compiler.

    XL C/C++ command
    For example:
    xlc -q64 -W "l,dll" -W "c,langlvl(extended),float(ieee),dll,exportall" -o libSample.so -I$JAVA_HOME/include -I$JAVA_HOME/include/zos Sample.c $JAVA_HOME/lib/j9vm/libjvm.x

    where $JAVA_HOME is the JAVA_HOME path of your IBM SDK installation. The header file jni.h exists under $JAVA_HOME/include and libjvm.x is in $JAVA_HOME/lib/j9vm.

    The XL C/C++ specific elements in the compile and link commands are as follows:
    Table 1. XL C/C++ command specific elements
    Option Description
    xlc The command that runs the XL C compiler.
    -q64 Option valid for 64-bit only. Tells the compiler to compile the target shared library for AMODE64 platforms.
    -W "l,dll" The option -W is passed to the link phase of the compiler. The linker creates a shared library .so file.
    -W "c,langlvl(extended),
    float(ieee),
    dll,exportall"
    The option -W is passed to the compile phase of the compiler.
    • langlvl(extended) enables language extensions that are used by the JNI header files, such as long long.
    • float(ieee) tells the compiler to generate binary IEEE754 floating-point numbers and instructions, which match the float and double primitive types of the Java language.
    • dll tells the compiler to produce DLL code. The DLL code can export or import functions and external variables.
    • exportall specifies that call functions in the shared library are callable by external programs.
    Open XL C/C++ command
    For example:
    ibm-clang -m64 -fvisibility=default -o libSample.so -I$JAVA_HOME/include -I$JAVA_HOME/include/zos Sample.c $JAVA_HOME/lib/j9vm/libjvm.x

    where $JAVA_HOME is the JAVA_HOME path of your IBM SDK installation.

    The Open XL C/C++ specific elements in the compile and link commands are as follows:
    Table 2. Open XL C/C++ command specific elements
    Option Description
    ibm-clang The command that runs the Open XL C compiler.
    -m64 Tells the compiler to compile the target shared library for AMODE64 platforms. 64-bit only.
    -fvisibility=default This option exports all externally defined functions and variables in the compilation unit so that a DLL application can use them.
    The remaining shared elements in the compile and link commands are as follows:
    Table 3. Common elements for XL and Open XL
    Option Description
    -o libSample.so The output file, which is the shared library that you want to build. The name (the text between lib and .so) must match the name that you provided to the System.load(filename) or System.loadLibrary(filename) Java APIs.
    -I$JAVA_HOME/include Tells the compiler to look in the $JAVA_HOME /include directory, in addition to the default directories, for header files (in this case, JNI header files). Change $JAVA_HOME to be the JAVA_HOME path of your IBM SDK installation.
    -I$JAVA_HOME/include/zos Tells the compiler to look in the $JAVA_HOME /include/zos directory, in addition to the default directories, for header files (in this case, JNI header files).
    Sample.c Your C program.
    $JAVA_HOME/lib/j9vm/libjvm.x The sidedeck file that enables native code to link and resolve the JNI and Invocation APIs.
  6. Run the Sample application.
    Because you used the System.loadLibrary Java API to specify the target shared library, you must make sure that either the LIBPATH environment variable or the java.library.path property includes the directory where the libSample.so library resides.
    For example:
    LIBPATH=. java Sample
    or
    java -Djava.library.path=. Sample
    The program outputs the following message:
    Printing from native

Results

Now, you are able to use the same framework to access native shared libraries from Java applications.