【问题标题】:Loading Native Library from java.library.path specifically专门从 java.library.path 加载本机库
【发布时间】:2016-04-25 05:45:13
【问题描述】:

我只是想制作一个玩具程序来将本机代码绑定到 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 代码(只是一个静态初始化器):

静止的 { System.out.println("System.getProperty(\"java.library.path\") 是:" + System.getProperty("java.library.path")); System.loadLibrary("mylib"); //System.load("/FULLPATH/mylib.so");// ***这工作*** }

我是如何尝试设置库路径的:

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 是上述打印语句的输出,当 # 运行“java TestIt” java -Djava.library.path=/FULLPATH:$DEFLT_LIB_PATH TestIt set LD_LIBRARY_PATH=/FULLPATH && java TestIt ##没有出现在lib的打印输出中 导出 LD_LIBRARY_PATH=/FULLPATH && java TestIt ##preppended /FULLPATH: 到 DEFLT_LIB_PATH

所有版本都打印出来,预期的例外是上面标有“##”的版本。

所有情况下的错误: Exception in thread "main" java.lang.UnsatisfiedLinkError: no mylib in java.library.path

完整路径没有空格或特殊字符,所以我很困惑为什么会这样。

为了完整性,也尝试过System.loadLibrary("mylib.so");

【问题讨论】:

    标签: java c gcc shared-libraries


    【解决方案1】:

    让我们看看 Javadoc 是怎么说的:

    加载具有指定库名称的动态库。包含本机代码的文件是从通常获取库文件的地方从本地文件系统加载的。此过程的细节取决于实现。 从库名到特定文件名的映射以系统特定的方式完成。

    由于您使用的是 CentOS 7,所以我将专注于 Linux。

    您面临的问题是您没有遵守不成文的 Linux 特定系统合同。 JVM 在 Linux 上所做的是将对System.loadLibrary("foo") 的调用转换为对dlopen("libfoo.so") 的调用。如果您重命名库并修复传递给 System.loadLibrary 的参数,它应该可以工作。

    我不知道有一份“官方”文件说明了这份合同,但它很可能存在于某个地方。

    如果你想玩得开心,你可以下载 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_loadfilename 参数,os::dll_load 本身调用dlopen(filename)

    【讨论】:

    • 哦,所以我必须遵守命名约定"lib%s.so" 才能使用该功能。谢谢它在那之后完美地工作了,谢谢。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2019-09-11
    • 1970-01-01
    • 2014-11-06
    • 1970-01-01
    • 1970-01-01
    • 2018-07-12
    • 1970-01-01
    相关资源
    最近更新 更多