具体从 java.library.path 加载本机库
Loading Native Library from java.library.path specifically
我只是想制作一个玩具程序来将本机代码绑定到 java 只是为了好玩。 我已经成功 能够使用 System.load("/FULLPATH/mylib.so")
制作程序 运行,但是在使用 System.loadLibrary()
从 java.library.path
加载库时遇到问题。
我正在使用的工具:
- gcc 4.8.5 20150623(红帽 4.8.5-4)
- java/javac 版本“1.8.0_66”(HotSpot 64 位)
- CentOS 7(64 位)
构建顺序(第一段中提到的两个版本相同)。
rm TestIt.class mylib.so TestIt.h
javac TestIt.java
javah -stubs TestIt
gcc -shared -I/$JDK8_HOME/include/ -I/$JDK8_HOME/include/linux/ -fPIC nativeTestItImpl.c -o mylib.so
Java 加载库的代码(简单的静态初始化器):
static {
System.out.println("System.getProperty(\"java.library.path\") is: " + System.getProperty("java.library.path"));
System.loadLibrary("mylib");
//System.load("/FULLPATH/mylib.so");// ***This works***
}
我是如何尝试设置库路径的:
java -Djava.library.path=/FULLPATH TestIt
java -Djava.library.path=/FULLPATH/mylib.so TestIt
java -Djava.library.path=. TestIt #appeared as '.'
java -Djava.library.path=/FULLPATH:$PATH TestIt
#NOTE: DEFLT_LIB_PATH was the output of the above print statement when
# running "java TestIt"
java -Djava.library.path=/FULLPATH:$DEFLT_LIB_PATH TestIt
set LD_LIBRARY_PATH=/FULLPATH && java TestIt ##did not appear in printout of lib
export LD_LIBRARY_PATH=/FULLPATH && java TestIt ##preppended /FULLPATH: to DEFLT_LIB_PATH
所有版本都打印为预期的例外,上面标有“##”的版本。
所有情况下的错误:
Exception in thread "main" java.lang.UnsatisfiedLinkError: no mylib in java.library.path
完整路径没有空格或特殊字符,所以我完全不知道为什么会这样。
也尝试 System.loadLibrary("mylib.so");
只是为了完整性。
让我们看看 Javadoc 是怎么说的:
Loads the dynamic library with the specified library name. A file containing native code is loaded from the local file system from a place where library files are conventionally obtained. The details of this process are implementation-dependent. The mapping from a library name to a specific filename is done in a system-specific manner.
由于您使用的是 CentOS 7,所以我将重点放在 Linux。
您面临的问题是您没有遵守 Linux 的不成文 system-specific 合同。 JVM 在 Linux 上所做的是将对 System.loadLibrary("foo")
的调用转换为对 dlopen("libfoo.so")
的调用。如果您重命名您的库并修复传递给 System.loadLibrary
的参数,它应该可以工作。
我不知道有 "official" 文档说明此合同,但它很可能存在于某处。
如果你想玩得开心,你可以下载OpenJDK并跟随调用链。您最终应该在 hotspot/src/os/linux/vm/os_linux.cpp
:
中定义的这段代码结束
bool os::dll_build_name(char* buffer, size_t buflen,
const char* pname, const char* fname) {
bool retval = false;
// Copied from libhpi
const size_t pnamelen = pname ? strlen(pname) : 0;
// Return error on buffer overflow.
if (pnamelen + strlen(fname) + 10 > (size_t) buflen) {
return retval;
}
if (pnamelen == 0) {
snprintf(buffer, buflen, "lib%s.so", fname);
retval = true;
} else [...]
os::dll_build_name
用于获取传递给 os::dll_load
的 filename
参数,后者本身调用 dlopen(filename)
.
我只是想制作一个玩具程序来将本机代码绑定到 java 只是为了好玩。 我已经成功 能够使用 System.load("/FULLPATH/mylib.so")
制作程序 运行,但是在使用 System.loadLibrary()
从 java.library.path
加载库时遇到问题。
我正在使用的工具:
- gcc 4.8.5 20150623(红帽 4.8.5-4)
- java/javac 版本“1.8.0_66”(HotSpot 64 位)
- CentOS 7(64 位)
构建顺序(第一段中提到的两个版本相同)。
rm TestIt.class mylib.so TestIt.h javac TestIt.java javah -stubs TestIt gcc -shared -I/$JDK8_HOME/include/ -I/$JDK8_HOME/include/linux/ -fPIC nativeTestItImpl.c -o mylib.so
Java 加载库的代码(简单的静态初始化器):
static { System.out.println("System.getProperty(\"java.library.path\") is: " + System.getProperty("java.library.path")); System.loadLibrary("mylib"); //System.load("/FULLPATH/mylib.so");// ***This works*** }
我是如何尝试设置库路径的:
java -Djava.library.path=/FULLPATH TestIt java -Djava.library.path=/FULLPATH/mylib.so TestIt java -Djava.library.path=. TestIt #appeared as '.' java -Djava.library.path=/FULLPATH:$PATH TestIt #NOTE: DEFLT_LIB_PATH was the output of the above print statement when # running "java TestIt" java -Djava.library.path=/FULLPATH:$DEFLT_LIB_PATH TestIt set LD_LIBRARY_PATH=/FULLPATH && java TestIt ##did not appear in printout of lib export LD_LIBRARY_PATH=/FULLPATH && java TestIt ##preppended /FULLPATH: to DEFLT_LIB_PATH
所有版本都打印为预期的例外,上面标有“##”的版本。
所有情况下的错误:
Exception in thread "main" java.lang.UnsatisfiedLinkError: no mylib in java.library.path
完整路径没有空格或特殊字符,所以我完全不知道为什么会这样。
也尝试 System.loadLibrary("mylib.so");
只是为了完整性。
让我们看看 Javadoc 是怎么说的:
Loads the dynamic library with the specified library name. A file containing native code is loaded from the local file system from a place where library files are conventionally obtained. The details of this process are implementation-dependent. The mapping from a library name to a specific filename is done in a system-specific manner.
由于您使用的是 CentOS 7,所以我将重点放在 Linux。
您面临的问题是您没有遵守 Linux 的不成文 system-specific 合同。 JVM 在 Linux 上所做的是将对 System.loadLibrary("foo")
的调用转换为对 dlopen("libfoo.so")
的调用。如果您重命名您的库并修复传递给 System.loadLibrary
的参数,它应该可以工作。
我不知道有 "official" 文档说明此合同,但它很可能存在于某处。
如果你想玩得开心,你可以下载OpenJDK并跟随调用链。您最终应该在 hotspot/src/os/linux/vm/os_linux.cpp
:
bool os::dll_build_name(char* buffer, size_t buflen,
const char* pname, const char* fname) {
bool retval = false;
// Copied from libhpi
const size_t pnamelen = pname ? strlen(pname) : 0;
// Return error on buffer overflow.
if (pnamelen + strlen(fname) + 10 > (size_t) buflen) {
return retval;
}
if (pnamelen == 0) {
snprintf(buffer, buflen, "lib%s.so", fname);
retval = true;
} else [...]
os::dll_build_name
用于获取传递给 os::dll_load
的 filename
参数,后者本身调用 dlopen(filename)
.