System.loadLibrary不起作用.链中第二个lib的UnsatisfiedLinkError

deg*_*nik 8 java java-native-interface loadlibrary java.library.path unsatisfiedlinkerror

我有java程序Client.class,它通过JNI使用cpp共享库libclient.so.libclient.so构建为共享并使用cpp共享库libhttp.so.

libclient.so和libhttp.so放在/home/client/lib64
Client.class 文件夹中/home/client/bin

客户端可以加载库

  1. System.load和环境变量LD_LIBRARY_PATH
  2. System.loadLibrary和-Djava.library.path

第一种方式很好.

export LD_LIBRARY_PATH = /home/client/lib64

java -classpath ./bin客户端

secon方式失败了.

java -classpath ./bin -Djava.library.path=./../lib64 Client

java.lang.UnsatisfiedLinkError: /home/client/lib64/libclient.so: libhttp.so: cannot open shared object file: No such file or directory
Run Code Online (Sandbox Code Playgroud)

当我将libhttp.so放入/ usr/lib64时,第二种方式正常.

如果我使用System.loadLibrary,为什么libclient.so在/ usr/lib64中寻找libhttp.so?如何在不将libhttp.so复制到/ usr/lib64的情况下修复它?

我的加载代码:

    //Try load from -Djava.library.path        
    boolean found = false;
    String lib = "client";
    try {
       System.loadLibrary(lib);
       found = true;
    } catch (UnsatisfiedLinkError e) {
       e.printStackTrace();
    }
    //Try load from LD_LIBRARY_PATH
    if (!found) {
       lib = "libclient.so";
       String ld_lib_path = System.getenv("LD_LIBRARY_PATH");
       String[] paths = ld_lib_path.split(":");
       for(int i=0; i<paths.length; i++) {
          String p = paths[i];
          File x = new File(p, lib);
          if (x.exists()) {
             System.load(x.getAbsolutePath());
             found = true;
             break;
          }
       }
    }
Run Code Online (Sandbox Code Playgroud)

附加信息.

如果我用ldd测试libclient.so然后我看到:libhttp.so => not found如果我设置export LD_LIBRARY_PATH =/home/client/lib64然后我看到:libhttp.so => /home/client/lib64/libhttp.so

Phi*_*ler 10

这样做的原因是libclient.so是从你的JVM加载的java.library.path.但是,当libclient.so尝试加载libhttp.so时,它对Java一无所知,只是使用常规的Linux方式加载共享库(动态链接器ld.so),它查找LD_LIBRARY_PATH和一些常见的目录,如/usr/lib64.

我可能会LD_LIBRARY_PATH从Java应用程序的启动脚本中使用set.如果您不想使用启动脚本,理论上可以LD_LIBRARY_PATH从流程本身进行设置.但是,Java不允许这样做(只有System.getenv(),没有System.setenv()),因此您需要编写一个从Java调用的小型C库并调用putenv()设置LD_LIBRARY_PATH.

如果构建libclient.so自身,则可以使用-rpath链接器标志指定动态链接器应查找其他所需库的路径.如果在此处指定相对路径,请小心,它将被解释为相对于正在运行的应用程序的当前工作目录,而不是相对于其位置libclient.so.要实现这一点,您需要使用$ORIGINas作为参数,-rpath并注意您的shell不会扩展它.

因此,如果您想拥有libclient.solibhttp.so在同一目录中,则需要使用

-rpath '$ORIGIN'
Run Code Online (Sandbox Code Playgroud)

作为构建时链接器的参数libclient.so.如果不直接调用链接器但让编译器调用它,则需要将以下内容添加到编译器的命令行:

-Wl,-rpath,'$ORIGIN'
Run Code Online (Sandbox Code Playgroud)

有关此内容的更多信息,请参见手册页ld.so.