使用 z/OS 共享库的示例

本例介绍了在z/OS系统上将本地共享库与 Java™ 应用程序一起使用的过程。

关于本任务

本任务演示如何创建一个 Java 应用程序,在本地共享库中加载和调用 C 函数。

程序

  1. 创建示例应用程序 "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();
        }
    }

    这个 Java 应用程序声明了一个静态本地方法 "Sample.printFromNative(),并从 "main方法中调用该本地方法。

    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.
    注意:"System.loadLibrary(libname)API 会在您提供的库名中添加前缀 "lib和后缀 ".so。 SDK 会在 "LIBPATH环境变量指定的库路径内搜索目标共享库。 如果目标本地共享库是 MVS 数据集,或者有特定的绝对路径或库名,请使用 "System.load(filename)API。
  2. 应用程序的 Java 部分已完成,因此您现在可以对其进行编译:
    javac Sample.java
  3. 使用 javac -h 命令为本机代码创建头文件:
    javac -h . Sample.java
    该命令会生成一个名为 "Sample.h的 C 头文件,其中包含适合本地应用程序实现的 JNI 方法签名。
  4. 创建名为 Sample.c的文件:
    #include <stdio.h>
    #include "Sample.h"
    
    JNIEXPORT void JNICALL Java_Sample_printFromNative(JNIEnv * env, jclass cls) {
      printf( "Printing from native\n" );
    }
    此文件提供 Java Sample.printFromNative() 方法的 C 本机实现。
  5. 将 "编译成 "Sample.c,链接并绑定到共享库 "libSample.so中,以便从 Java 应用程序中动态加载和调用。 您可以使用XL C/C++Open XL C/C++编译器。

    XL C/C++命令
    对于 31 位应用程序:
    xlc -W "l,xplink,dll" -W "c,langlvl(extended),float(ieee),xplink,dll,exportall" -o libSample.so -I/$JAVA_HOME/include Sample.c  /$JAVA_HOME/lib/s390x/j9vm/libjvm.x
    其中,$JAVA_HOME 是 IBM SDK 安装的 JAVA_HOME 路径。

    对于 64 位应用程序:

    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/s390x/libjvm.x

    其中,$JAVA_HOME 是 IBM SDK 安装的 JAVA_HOME 路径。 头文件 "jni.h存在于 "$JAVA_HOME/include下,"libjvm.x"位于 "$JAVA_HOME/lib/""s390x/""j9vm中。

    编译和链接命令中 "XL C/C++的具体内容如下:
    表 1. XL C/C++命令特定元素
    选项 描述
    xlc 运行 XL C 编译器的命令。
    -q64 该选项仅适用于 64 位。 让编译器编译 AMODE64 平台的目标共享库。
    --W"l,xplink,dll" 将选项 -W 传递至编译器的链接阶段。 链接器创建了一个共享库 ".so文件, and uses the high-performance linkage XPLINK
    --W"c,langlvl(扩展)、
    float(ieee)、
    xplink,
    dll,exportall"
    将选项 -W 传递到编译器的编译阶段。
    • langlvl(extended) 会启用 JNI 头文件所使用的语言扩展,例如 long long
    • float(ieee) 指示编译器生成与 Java 语言的 floatdouble 基本类型匹配的二进制 IEEE754 浮点数和指令。
    • xplink告诉编译器使用高性能链接 XPLINK,它与 Java 虚拟机使用的链接相匹配。 在 31 位平台上,语言环境支持过渡到其他联接(如系统联接),但要付出另一个路径长度的代价。
    • dll 指示编译器生成 DLL 代码。 DLL 代码可以导出或导入函数和外部变量。
    • exportall 指定可由外部程序调用共享库中的调用函数。
    Open XL C/C++命令
    例如:
    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

    其中 $JAVA_HOME 是IBMSDK 安装的 JAVA_HOME 路径。

    编译和链接命令中 "Open XL C/C++的具体内容如下:
    表 2. Open XL C/C++命令特定元素
    选项 描述
    ibm-clang 运行Open XLC 编译器的命令。
    -m64 让编译器编译 AMODE64 平台的目标共享库。 仅限 64 位。
    -fvisibility=default 该选项导出编译单元中所有外部定义的函数和变量,以便 DLL 应用程序可以使用它们。
    编译和链接命令中的其余共享元素如下:
    表 3. XL 和Open XL的共同要素
    选项 描述
    -o libSample.so 这是一个输出文件,它是您想要构建的共享库。 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 目录以及默认目录中查找头文件(此处为 JNI 头文件)。 将 $JAVA_HOME 改为IBMSDK 安装的 JAVA_HOME 路径。
    --I 指示编译器在 $JAVA_HOME /include/zos 目录以及默认目录中查找头文件(此处为 JNI 头文件)。
    Sample.c 您的 C 程序。
    $JAVA_HOME/lib/j9vm/libjvm.x 使本地代码能够链接和解析 JNI 和调用 API 的侧甲板文件。
  6. 运行 Sample 应用程序。
    由于您使用了 "System.loadLibraryJava API 来指定目标共享库,因此必须确保 "LIBPATH环境变量或 "java.library.path属性包含 "libSample.so库所在的目录。
    例如:
    LIBPATH=. java Sample
    java -Djava.library.path=. Sample
    该程序输出以下消息:
    Printing from native

结果

现在,您可以使用相同的框架从 Java 应用程序访问本地共享库。