使用 z/OS 共享库的示例
本例介绍了在z/OS系统上将本地共享库与 Java™ 应用程序一起使用的过程。
关于本任务
本任务演示如何创建一个 Java 应用程序,在本地共享库中加载和调用 C 函数。
程序
- 创建示例应用程序 "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 应用程序声明了一个静态本地方法 "
During the static class initialization block that is run when theSample.printFromNative()
,并从 "main
方法中调用该本地方法。Sample
class is first loaded, theSystem.loadLibrary("Sample")
call loads the target native librarylibSample.so
.注意:"System.loadLibrary(libname)
API 会在您提供的库名中添加前缀 "lib
和后缀 ".so
。 SDK 会在 "LIBPATH
环境变量指定的库路径内搜索目标共享库。 如果目标本地共享库是 MVS 数据集,或者有特定的绝对路径或库名,请使用 "System.load(filename)
API。 - 应用程序的 Java 部分已完成,因此您现在可以对其进行编译:
javac Sample.java
- 使用 javac -h 命令为本机代码创建头文件:
该命令会生成一个名为 "javac -h . Sample.java
Sample.h
的 C 头文件,其中包含适合本地应用程序实现的 JNI 方法签名。 - 创建名为
Sample.c
的文件:
此文件提供 Java#include <stdio.h> #include "Sample.h" JNIEXPORT void JNICALL Java_Sample_printFromNative(JNIEnv * env, jclass cls) { printf( "Printing from native\n" ); }
Sample.printFromNative()
方法的 C 本机实现。 - 将 "编译成 "
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 语言的float
和double
基本类型匹配的二进制 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 theSystem.load(filename)
orSystem.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 的侧甲板文件。 - 运行
Sample
应用程序。由于您使用了 "System.loadLibrary
Java API 来指定目标共享库,因此必须确保 "LIBPATH
环境变量或 "java.library.path
属性包含 "libSample.so
库所在的目录。例如:
或LIBPATH=. java Sample
java -Djava.library.path=. Sample
该程序输出以下消息:Printing from native
结果
现在,您可以使用相同的框架从 Java 应用程序访问本地共享库。