JNI 运行时链接
特定于 AIX 系统的信息
对于运行时链接,可以使用 -brtl 装入程序选项来链接应用程序。 如果运行时链接导致符号冲突,那么应用程序必须通过重命名应用程序端的符号或关闭运行时链接来解决该冲突。
AIX 中的动态链接
cc_r -qmkshrobj [-qarch=ppc | -q64] -Ijava_install_dir/include
-o libnm.a nm.c
-qmkshrobj
选项可禁用运行时链接。 有关共享对象文件、运行时链接以及使用 cc
和 ld
命令行选项的更多信息,请参阅:- 在 AIX 上开发和移植 C 和 C++ 应用程序 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 共享对象的更多信息,请参阅 C 和 C++ Application Development on AIX 。 转至 https://www.ibm.com/redbooks 并搜索 "SG245674"。
如果在 JNI 本机代码程序上设置 setuid 或 setgid 属性,那么该设置会更改有效的 LIBPATH 环境变量。 这种更改可能会引起程序发生意外或不正确的行为。 有关此用法的更多信息,请参阅 在 AIX 上开发和移植 C 和 C++ 应用程序 ,网址为 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
另一个选项是在创建线程时使用 AIX pthread_attr_setscope
函数将线程的作用域属性预设为 PTHREAD_SCOPE_SYSTEM 。
- 共享对象
- 共享对象是在 XCOFF 标题中具有 SRE(共享重复性)位设置的单个对象文件。 SRE 位可以识别该文件动态链接到的链接程序。 这些文件通常具有格式为 <filename> .o 的名称,但它们也可以命名为 lib<name> .a,以允许链接程序使用 -lname 选项来搜索这些文件;但这些文件不是归档库文件。
- 共享库
- 共享库是“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。 如果您尝试使用 System.loadLibrary("testlibA")
之类的命令在Java程序中加载 testlibA 库,JVM首先会在启动的可执行程序映像中查找名为 JNI_OnLoad_testlibA( 的例程。如果找到该例程,JVM将使用该静态绑定库提供JNI定义。 如果未找到例程,JVM 将回退以在 -Djava.library.path(或 LIBPATH)中指定的路径中查找来动态装入 testlibA 库(例如 libtestlibA.so)。
在 AIX上,除了通过指定 -brtl来启用运行时链接外,还必须使用指定的选项 -bexpall 进行构建。 该过程可确保启动程序导出符号(例如 JNI_OnLoad_testlibA()),还允许可执行程序装入的共享库(例如 JVM 的共享库)查找符号。 为使 JVM 能够静态链接,它必须能够在进行任何动态链接尝试之前在可执行程序中重新查找。
$ cc_r -qpic -brtl -bexpall -brtl testlibA.o testlibB.o -o <launcher>
其中 <launcher> 是包含 testlibA 和 testlibB 库的映像的可执行程序的名称,并且是通过调用 API 启动 JVM 的 Java 启动程序。库初始化例程 JNI_OnLoad_L, 对于库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 文件。
要确保 JNI 库导出 Java 应用程序在运行时必须解析的函数,可以使用 nm 工具来检查该库。 例如,名为 libjnitest.so 且包含 JNI 例程 fooImpl
和 barImpl
的 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 man 文档并搜索 dlopen。
Linux 中的静态链接
除了动态链接,您还可以静态链接到 JNI 库。 静态库可以合并到使用调用 API 启动 JVM 进程的定制启动程序的映像中。
请考虑以下两个静态库:testlibA 和 testlibB。 如果您尝试使用 System.loadLibrary("testlibA")
之类的命令在Java程序中加载 testlibA 库,JVM首先会在启动的可执行程序映像中查找名为 JNI_OnLoad_testlibA( 的例程。如果找到该例程,JVM将使用该静态绑定库提供JNI定义。 如果未找到例程,JVM 将回退以在 -Djava.library.path(或 LD_LIBRARY_PATH)中指定的路径中查找来动态装入 testlibA 库(例如 libtestlibA.so)。
在 Linux 上,您必须使用指定的选项 -rdynamic 进行构建,以确保启动器导出符号(例如 JNI_OnLoad_testlibA( ),并允许可执行程序(例如JVM)加载的共享库查找符号。 为使 JVM 能够静态链接,它必须能够在进行任何动态链接尝试之前在可执行程序中重新查找。 如果不指定 -rdynamic,那么仍会从可执行程序中导出非静态符号,但这些符号对于该程序装入的共享库不可见。 以下示例显示了 -rdynamic 的用法:
$ cc -rdynamic testlibA.o testlibB.o -o <launcher>
库初始化例程 JNI_OnLoad_L, 对于库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% 中存在的库。 该变量必须始终指向 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。 如果您尝试使用 System.loadLibrary("testlibA")
之类的命令在Java程序中加载 testlibA 库,JVM首先会在启动的可执行程序映像中查找名为 JNI_OnLoad_testlibA( 的例程。如果找到该例程,JVM将使用该静态绑定库提供JNI定义。 如果未找到例程,JVM 将回退以在 -Djava.library.path(或 PATH)中指定的路径中查找来动态装入 testlibA 库(例如 testlibA.dll)。
在构建启动程序可执行程序时, Windows 不会强制指定任何特殊选项。
库初始化例程 JNI_OnLoad_L, 对于库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 文件。
要确保 JNI 库导出 Java 应用程序在运行时必须解析的函数,您可以使用 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。 如果您尝试使用 System.loadLibrary("testlibA")
之类的命令在Java程序中加载 testlibA 库,JVM首先会在启动的可执行程序映像中查找名为 JNI_OnLoad_testlibA( 的例程。如果找到该例程,JVM将使用该静态绑定库提供JNI定义。 如果未找到例程,JVM 将回退以在 -Djava.library.path(或 LIBPATH)中指定的路径中查找来动态装入 testlibA 库(例如 libtestlibA.so)。
Wc,DLL
,以确保可执行程序构建为 DLLWc,EXPORTALL
,以确保导出可执行程序中的符号,并使其可供该程序装入的共享库查找
cc -c -Wc,DLL,EXPORTALL launcher.c -o launcher.o
cc testlibA.o testlibB.o launcher.o -o launcher
或者,您也可以除去 EXPORTALL
,在这种情况下,程序通过使用 #pragma export
来导出特定符号。 有关更多信息,请参阅 #pragma 导出。
库初始化例程 JNI_OnLoad_L, 对于库L,必须返回JNI_VERSION_1_8(0x00010008).