通过JNI从其他共享库加载依赖的.so

问题描述 投票:1回答:2

我想从其他libb.so中调用liba.so的某些功能。libb.so是动态的,因此该库实现了我在JNI中使用System.loadLibrary(“ b”)加载的本机方法。首先,我使用java.library.path为jni中的.so设置了完整路径,但是当我运行Java程序时,在加载共享库libb.so时,它给出以下错误:

Exception in thread "main" java.lang.UnsatisfiedLinkError: x/y/z/libb.so: liba.so: cannot open shared object file: No such file or directory.
at java.lang.ClassLoader$NativeLibrary.load(Native Method)
        at java.lang.ClassLoader.loadLibrary0(ClassLoader.java:1941)
        at java.lang.ClassLoader.loadLibrary(ClassLoader.java:1857)
        at java.lang.Runtime.loadLibrary0(Runtime.java:870)
        at java.lang.System.loadLibrary(System.java:1122)
  1. 首先,我在编译过程中使用以下方法将共享库liba.so与其他共享库libb.so链接在一起

    g ++ -shared -o libb.so -fPIC b.cc -L / x / y / z -la

    (例如liba.so的完整路径为/ x / y / z)

  2. 在JNI中,我已实用地设置了java.library.path,其中包含liba.so,libb.so的完整路径,然后我习惯于将JNI本机库libb.so加载为

(假设libb.so的完整路径是a / b / c,liba.so的完整路径是x / y / z。)

String libpath = "x/y/z" + "a/b/c";
System.setProperty( "java.library.path", libpath);
    try {
        Field fieldSysPath = ClassLoader.class.getDeclaredField("sys_paths");
        fieldSysPath.setAccessible( true );
        fieldSysPath.set( null, null );
       }
    catch (Exception e)
      {
        System.out.println(e);
      }

//在这里,我能够打印/获取正确的java.library.path。 (两个共享库的路径均正确保存到java.library.path中)

static {
    System.loadLibrary("b");
}

当我的java程序加载此静态块动态库时,出现以下错误:

线程“主”中的异常java.lang.UnsatisfiedLinkError:x / y / z / liba.so:libb.so:无法打开共享库文件:没有这样的文件或目录。

注:当我在LD_LIBRARY_PATH中设置liba.so的路径时,此工作正常,没有任何错误。但我不想在SHELL中设置LD_LIBRARY_PATH。我只想在程序本身中设置java.library.path或LD_LIBRARY_PATH。

预先感谢!

linux java-native-interface shared-libraries dynamic-loading java.library.path
2个回答
0
投票

从本地库加载从属库是纯粹的操作系统操作,因此不在Java控制范围之内。不幸的是,您无法使用Java提供的工具解决此问题。

您已经指出,在Linux库中,可以通过LD_LIBRARY_PATH环境变量来设置搜索路径,但是无法修改已经运行的JVM进程的环境变量(请参阅here,并建议不要真正使用hack using gdb可用于非调试情况)。

您所描述的问题已作为Windows https://bugs.openjdk.java.net/browse/JDK-8213772的JDK错误归档,并带有注释我们实际上无能为力

但是,对于您的情况,应该有一个简单的解决方案:

在加载libb.so之前先显式加载依赖库liba.so

    static {
        System.loadLibrary("a");
        System.loadLibrary("b");
    }

如果有多个从属库和更深的从属层次结构级别,请以相反的顺序手动加载所有从属库。


0
投票

假设您控制共享对象liba.solibb.so的位置,请用libb.so编译embedded RPATH set so that it can locate liba.so共享对象。

如果两个共享库位于shame目录中,则可以使用:

RPATH

liba.so本身可以工作,但是我想使用g++ -shared -o libb.so -fPIC b.cc -L/x/y/z -la -Wl,-rpath,'$ORIGIN/.' 清楚地表明结果是目录。如果您具有共同的$ORIGIN$ORIGIN/.目录树,则始终对两者使用bin可执行文件和共享对象也是IMO的一个好主意。)

lib将在$ORIGIN/../lib共享对象中设置-Wl,-rpath,'$ORIGIN/.,以便运行时链接程序在RPATH所在的同一目录中搜索libb.so

© www.soinside.com 2019 - 2024. All rights reserved.