简体   繁体   English

从java.library.path专门加载Native Library

[英]Loading Native Library from java.library.path specifically

I was just trying to make a toy program to bind native code to java just for fun. 我只是试图制作一个玩具程序,以将本机代码绑定到Java只是为了好玩。 I have successfully been able to make the program run using System.load("/FULLPATH/mylib.so") , but having trouble loading libraries specifically from java.library.path using System.loadLibrary() . 已经能够使用System.load("/FULLPATH/mylib.so") 成功运行该程序,但是使用System.loadLibrary()java.library.path专门加载库时遇到了麻烦。

Tools I'm using: 我使用的工具:

  • gcc 4.8.5 20150623 (Red Hat 4.8.5-4) gcc 4.8.5 20150623(Red Hat 4.8.5-4)
  • java/javac version "1.8.0_66" (HotSpot 64 bit) java / javac版本“ 1.8.0_66”(HotSpot 64位)
  • CentOS 7 (64 bit) CentOS 7(64位)

Build sequence (same for both versions mentioned in first paragraph). 生成顺序(第一段中提到的两个版本相同)。

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 code to load the library (simply a static initializer): 加载库的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***
    }

How I've tried to set the library path: 我如何尝试设置库路径:

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

All version printed out as, expected exception those labeled with the "##" above. 所有版本均以预期的例外(上面带有“ ##”标记的版本)打印。

Error in all cases: Exception in thread "main" java.lang.UnsatisfiedLinkError: no mylib in java.library.path 在所有情况下均发生错误: Exception in thread "main" java.lang.UnsatisfiedLinkError: no mylib in java.library.path

Full path has no spaces or special characters so I'm quite lost why this is the case. 完整路径没有空格或特殊字符,因此我完全不知道为什么会出现这种情况。

Also have tried System.loadLibrary("mylib.so"); 还尝试了System.loadLibrary("mylib.so"); just for completeness. 只是为了完整性。

Let's check what the Javadoc says: 让我们检查一下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. 从库名到特定文件名的映射以系统特定的方式完成。

Since you are using CentOS 7 so I will focus on Linux. 由于您使用的是CentOS 7,因此我将重点介绍Linux。

The issue you are facing is that you don't follow the unwritten system-specific contract for Linux. 您面临的问题是您没有遵循针对Linux的未成文的系统特定合同。 What the JVM does on Linux is to transform a call to System.loadLibrary("foo") to a call to dlopen("libfoo.so") . JVM在Linux上的作用是将对System.loadLibrary("foo")的调用转换为对dlopen("libfoo.so")的调用。 If you rename your library and fix the argument passed to System.loadLibrary it should work. 如果您重命名库并修复传递给System.loadLibrary的参数,则它应该可以工作。

I am not aware of an "official" documentation stating this contract but it most likely exist somewhere. 我不知道有一份说明该合同的“官方”文档,但它很可能存在于某处。

If you want to have fun, you can download OpenJDK and follow the call chain. 如果您想玩得开心,可以下载OpenJDK并遵循电话链。 You should eventually end up on this piece of code defined in hotspot/src/os/linux/vm/os_linux.cpp : 您最终应该结束在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 is used to get the filename parameter which is passed to os::dll_load which itself invokes dlopen(filename) . os::dll_build_name用于获取filename参数,该参数传递给os::dll_load ,后者本身会调用dlopen(filename)

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM