6

Mam program klienta java Client.class, który używa biblioteki współdzielonej cpp libclient.so przez JNI. libclient.so jest zbudowany jako udostępniony i używa biblioteki współdzielonej cpp libhttp.so.System.loadLibrary nie działa. UnsatisfiedLinkError dla drugiej biblioteki w łańcuchu

libclient.so i libhttp.so są umieszczone w folderze /home/client/lib64
Client.class jest umieszczony w /home/client/bin

klient może załadować bibliotekę z

  1. System.load i zmienna środowiskowa LD_LIBRARY_PATH
  2. System.loadLibrary i -Djava.library.path

Pierwszy sposób działa dobrze.

export LD_LIBRARY_PATH = /home/client/lib64

java -classpath ./bin Klienta

Sposób secon zawiedzie.

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 

Kiedy kładę libhttp.so w katalogu/usr/lib64 drugi sposób działa dobrze.

Dlaczego libclient.so szuka libhttp.so w/usr/lib64, jeśli używam System.loadLibrary? Jak mogę to naprawić bez kopiowania biblioteki libhttp.so do/usr/lib64?

Mój kod ładowania:

//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; 
      } 
     } 
    } 

dodatkowe informacje.

Gdybym przetestować libclient.so z ldd potem widzę: libhttp.so => ​​Nie znaleziono Jeżeli ustawić export LD_LIBRARY_PATH =/home/client/lib64 potem widzę: libhttp.so => ​​/ home/client/lib64/libhttp.so

Odpowiedz

10

Powodem jest to, że libclient.so jest ładowany z maszyny JVM, która wygląda w java.library.path. Jednakże, gdy libclient.so próbuje załadować libhttp.więc nic nie wie o Javie i używa zwykłego linuksowego sposobu ładowania bibliotek współdzielonych (dynamiczny linker ld.so), który wygląda w LD_LIBRARY_PATH i niektórych popularnych katalogach, takich jak /usr/lib64.

Prawdopodobnie użyłbym zestawu LD_LIBRARY_PATH ze skryptu startowego aplikacji Java. Jeśli nie chcesz używać skryptu startowego, możesz w teorii ustawić LD_LIBRARY_PATH z samego procesu. Jednak Java nie pozwala na to (jest tylko System.getenv(), a nie System.setenv()), więc musisz napisać małą bibliotekę C, która jest wywoływana z Javy i wywołuje putenv() ustawienie LD_LIBRARY_PATH.

Jeśli sam zbudujesz libclient.so, możesz użyć flagi linkera -rpath, aby określić ścieżkę, w której dynamiczny linker powinien szukać dalszych wymaganych bibliotek. Zachowaj ostrożność, jeśli podasz tutaj ścieżkę względną, zostanie ona zinterpretowana jako względna względem bieżącego katalogu roboczego uruchomionej aplikacji, a nie w odniesieniu do lokalizacji libclient.so. Aby to osiągnąć, musisz użyć $ORIGIN jako argumentu dla -rpath i uważaj, aby twoja powłoka tego nie rozszerzyła.

Tak więc, jeśli chcesz mieć libclient.so i libhttp.so w tym samym katalogu, trzeba użyć

-rpath '$ORIGIN' 

jako argument na łącznik przy budowie libclient.so. Jeśli nie wywołać łącznik bezpośrednio, ale niech kompilator nazwać, trzeba dodać następujące linii komend naszego kompilatora:

-Wl,-rpath,'$ORIGIN' 

Więcej informacji na ten temat można znaleźć w man page for ld.so.

1

Nie mam dobrej odpowiedzi na to pytanie.

Ale znalazłem kilka dobrych sposobów.

  1. Umieść libhttp.so w udostępnionej lokalizacji dla bibliotek, na przykład/usr/lib64.
  2. Ustaw ścieżkę do biblioteki libhttp.so na LD_LIBRARY_PATH.
  3. Wbuduj libclient.so z libhttp.so wewnątrz.
  4. Użyj -rpath podczas budowania libclient.so.
0

Dla prawidłowego odnośnika biblioteki (z java.library.path) dla różnych systemów operacyjnych muszą mieć różne nazwy:

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

niż można zadzwonić z Java:

System.loadLibrary("http"); 
Powiązane problemy