6

我有java程序Client.class,它通過JNI使用cpp共享庫libclient.so。 libclient.so被構建爲共享並使用cpp共享庫libhttp.so。System.loadLibrary不起作用。鏈中第二個庫的UnsatisfiedLinkError

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客戶

的塞康的方式失敗。

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 

當我把libhttp.so到/ usr/lib64的第二種方式工作正常。

爲什麼libclient.so在/ usr/lib64中查找libhttp.so,如果我使用System.loadLibrary? 我該如何修復它而不將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; 
      } 
     } 
    } 

的附加信息。

如果我有LDD測試libclient.so然後我看到:libhttp.so =>找不到 如果我設置出口LD_LIBRARY_PATH = /家庭/客戶/ lib64下,然後我看到:libhttp.so => /家庭/客戶機/ lib64/libhttp.so

回答

10

原因是libclient.so是從您的JVM加載的,它看起來在java.library.path。但是,當libclient.so嘗試加載libhttp時。因此,它對Java一無所知,只是使用常規的Linux加載共享庫的方式(動態鏈接程序ld.so),它在LD_LIBRARY_PATH和一些常用目錄(如/usr/lib64)中查找。

我可能會使用從您的Java應用程序的啓動腳本中設置的LD_LIBRARY_PATH集。如果您不想使用啓動腳本,理論上您可以在流程內設置LD_LIBRARY_PATH。但是,Java不允許這樣做(只有System.getenv(),而不是System.setenv()),所以您需要編寫一個從Java調用的小型C庫並調用putenv()設置LD_LIBRARY_PATH

如果您自己構建libclient.so,則可以使用鏈接器標誌-rpath來指定動態鏈接程序應查找其他所需庫的路徑。如果您在此指定相對路徑,請小心,它將解釋爲相對於當前正在運行的應用程序的工作目錄,而不是相對於libclient.so的位置。爲了達到這個目的,你需要使用$ORIGIN作爲-rpath的參數,並且要小心你的shell不會擴展它。

所以,如果你想擁有libclient.solibhttp.so在同一目錄下,你需要建立libclient.so時使用

-rpath '$ORIGIN' 

作爲參數傳遞給鏈接器。如果你不直接調用連接器而讓你的編譯器調用它,你需要將以下添加到您的編譯器的命令行:

-Wl,-rpath,'$ORIGIN' 

更多這方面的信息可以在man page for ld.so找到。

1

我對這個問題沒有很好的答案。

但我發現了幾種好方法。

  1. 將libhttp.so放入庫的共享位置,例如/ usr/lib64。
  2. 將路徑libhttp.so放入LD_LIBRARY_PATH中。
  3. 在libhttp.so中創建libclient.so。
  4. 在構建libclient.so期間使用-rpath。
0

對於庫的正確查找(從的java.library.path)爲不同的操作系統必須有不同的名稱:

  • 的Linux:libhttp.so
  • 的Windows:http.dll

比你可以從Java調用:

System.loadLibrary("http");