Jak naprawić błąd UnsatisfiedLinkError (nie można znaleźć bibliotek zależnych) w projekcie JNI

85

Pracuję nad projektem Java, który używa JNI. JNI wywołuje bibliotekę niestandardową, którą sam napisałem, powiedzmy mylib.dll, która zależy od biblioteki innej firmy, libsndfile-1.dll.

Kiedy uruchamiam program, ulega awarii z

java.lang.UnsatisfiedLinkError:  C:\...path...\mylib.dll: Can't find dependent libraries.

Przeszukałem tę witrynę (i inne) i wypróbowałem kilka poprawek:

  1. Pobiegłem chodzik dla uzależnień. DW przekazał kilka ostrzeżeń - że dwie biblioteki wymagane przez libsndfile, MPR.DLL i SHLWAPI.DLL, mają „nierozwiązane importy” - ale DW FAQ powiedział, że te ostrzeżenia można bezpiecznie zignorować.

  2. Poprawiłem nazwy metod w mylib.dll, zgodnie z sugestią tutaj . Nazwy metod zostały w jakiś sposób zniekształcone przez kompilator, ale dodałem flagi konsolidatora i nazwy metod dll są teraz dokładnie zgodne z tymi w moim pliku nagłówkowym jni.

  3. Umieściłem wszystkie te biblioteki DLL w tym samym katalogu - tym samym katalogu, co plik .jar, który je wywołuje - aby upewnić się, że znajdują się na właściwej ścieżce.

Nie ma kości.

Czy ktoś ma pojęcie o co chodzi?

Programuję w Visual Studio 2010 na MacBooku Pro (przez Parallels). Przeprowadzam testy w systemie Windows XP na laptopie Toshiba.

dB '
źródło
1
czy ustawiłeś -Djava.library.path?
Jochen Bedersdorfer
Właściwie nie, ponieważ nie uruchamiam programu z wiersza poleceń. Piszę bibliotekę do przetwarzania (processing.org), a przetwarzanie jest odpowiedzialne za uruchomienie mojego kodu. Sprawdziłem jednak ścieżkę biblioteki java w czasie wykonywania i znajduje się na niej folder zawierający moje biblioteki DLL.
dB '23
Jak powiedziałem, wszystkie biblioteki DLL znajdują się w tym samym folderze, obok mojego pliku .jar. Więc nie sądzę, że problem polega na tym, że nie są na ścieżce. Mimo wszystko dziękuję.
dB '23
7
W systemie Windows musieliśmy umieścić pliki .dll w katalogu [JRE] \ bin (w tym samym miejscu, w którym znajduje się java.exe itp.), Aby Java wyświetlała je automatycznie, bez konieczności modyfikowania opcji wiersza poleceń lub zmiennych środowiskowych.
QuantumMechanic
4
Hmm ... ok, próbowałem umieścić wszystkie moje pliki .dll w [JRE] \ bin. To działa!
dB '23

Odpowiedzi:

52

Jestem prawie pewien, że ścieżka klas i ścieżka wyszukiwania bibliotek współdzielonych mają ze sobą niewiele wspólnego. Zgodnie z The JNI Book (która wprawdzie jest stara), w systemie Windows, jeśli nie używasz java.library.pathwłaściwości systemowej, biblioteka DLL musi znajdować się w bieżącym katalogu roboczym lub w katalogu wymienionym w systemie WindowsPATH zmiennej środowiskowej .


Aktualizacja:

Wygląda na to, że firma Oracle usunęła plik PDF ze swojej witryny internetowej. Zaktualizowałem powyższy link, aby wskazywał na przykład pliku PDF mieszkającego na Uniwersytecie Teksasu w Arlington.

Możesz także przeczytać wersję HTML specyfikacji JNI firmy Oracle . To znajduje się w sekcji Java 8 witryny Java i mam nadzieję, że będzie tam przez jakiś czas.


Aktualizacja 2:

Przynajmniej w Javie 8 (nie sprawdzałem wcześniejszych wersji) możesz:

java -XshowSettings:properties -version

aby znaleźć ścieżkę wyszukiwania bibliotek współdzielonych. Poszukaj wartości java.library.pathwłaściwości w tych danych wyjściowych.

QuantumMechanic
źródło
2
Tak, CLASSPATHw ogóle nie jest używany. Nie jestem też pewien, czy cwdw ogóle jest używany. java.library.pathlub po prostu PATHzadziała. @dB ', miejsce, w którym je teraz masz, jest nieprawidłowe .
Ernest Friedman-Hill
Wielkie dzięki! Myślę, że częścią problemu było zamieszanie z mojej strony między zmienną środowiskową PATH systemu Windows, java.library.path i java CLASSPATH. To wszystko ma teraz więcej sensu.
dB '23
Czy możesz wyjaśnić, w jaki sposób rozwiązałeś ten problem?
SL_User,
5
@SL_User Myślę, że jeśli dodasz katalog, w którym znajdują się biblioteki do zmiennej środowiskowej „ścieżka” i zrestartujesz wiersz poleceń lub terminal, powinno to naprawić. Java szuka słoików w ścieżce klas i bibliotek pod ścieżką.
xxjjnn
1
Opierając się na tej odpowiedzi, wygląda na to, że to polecenie dla Update 2 było dostępne przynajmniej od wersji Java 7: stackoverflow.com/a/8472139/901641
ArtOfWarfare
18

Chcę poinformować o tym interesującym przypadku, po wypróbowaniu wszystkich powyższych metod błąd nadal występuje. Dziwne jest to, że działa na komputerze z systemem Windows 7, ale w systemie Windows XP nie. Następnie używam walkera zależności i stwierdziłem, że w systemie Windows XP nie ma VC ++ Runtime jako mojego wymagania dll. Po zainstalowaniu pakietu VC ++ Runtime tutaj działa jak urok. Przeszkadzało mi to, że ciągle powtarza Nie można znaleźć bibliotek zależnych, podczas gdy intuicyjnie istnieje biblioteka dll zależna od JNI, jednak ostatecznie okazuje się, że dll zależna od JNI wymaga innej biblioteki zależnej. Mam nadzieję, że to pomoże.

longbkit
źródło
4
Wiadomość jest poprawna, choć w tym przypadku myląca. Miałem zarówno VC ++ brakujące czasy pracy na polu badań i biblioteki skompilowany w trybie debugowania (w zależności od niezarejestrowanych -redistributable czasy pracy debugowania). Dependency Walker bardzo pomógł w rozwiązaniu tego problemu.
Johnny Baloney,
miał ten sam problem przy użyciu biblioteki jnetpcap. zależność winpcap nie była już zainstalowana na komputerze, a komunikat o wyjątku był mylący
BlackFlag
Myślę, że to może być moja sprawa.
I.Tyger
W dzisiejszych czasach chodzik na uzależnieniach jest dość „długi w zębach”. Nie można w ogóle otworzyć najnowszej biblioteki dll systemu Windows 10/64-bitowego, więc nadal nie mam pojęcia, której biblioteki brakuje ...
Mark Storer
5

Sprawdź, czy ścieżka do biblioteki jest prawidłowa, czy nie. Oczywiście możesz użyć następującego kodu, aby sprawdzić ścieżkę do biblioteki: System.out.println(System.getProperty("java.library.path"));

Możesz wyznaczyć java.library.path podczas uruchamiania aplikacji Java:

java -Djava.library.path=path ...
caopeng
źródło
4

Jeśli załadujesz 32-bitową wersję swojej biblioteki dll za pomocą 64-bitowego środowiska JRE, możesz mieć ten problem. To był mój przypadek.

EFalco
źródło
Najprawdopodobniej jest to również mój przypadek; jeśli ktoś jest świadomy znanych obejść, byłbym zainteresowany; z wyjątkiem ładowania wersji 64-bitowej, ponieważ w tym przypadku procesem nie jest dll, ale chromedriver.exesterownik Selenium dla Chrome, który, o ile wiem, występuje tylko w wersji 32-bitowej.
SantiBailors
4

Miałem identyczny problem jak na komputerze XP podczas instalacji javacviw opencvpołączeniu z Eclipse. Okazało się, że brakuje mi następujących plików:

  • msvcp100.dll
  • msvcr100.dll

Po ich zainstalowaniu projekt został skompilowany i działał poprawnie.

Rob van Riswick
źródło
Mam podobny problem, który znika po zainstalowaniu pakietu redystrybucyjnego „Microsoft Visual C ++ 2010 SP1 (x86)”
Kirill Mikhailov
2
  • Krótka odpowiedź: w przypadku błędu „nie można znaleźć biblioteki zależnej” sprawdź swoją $ PATH (odpowiada punktowi 3 poniżej)
  • Długa odpowiedź:
    1. Czysty świat java: jvm używa „Classpath” do wyszukiwania plików klas
    2. Świat JNI (granica java / natywna): jvm używa „java.library.path” (domyślnie $ PATH) do znajdowania bibliotek dll
    3. czysty świat natywny: kod natywny używa $ PATH do ładowania innych bibliotek dll
user2038596
źródło
2

Znalazłem świetny artykuł napisany przez znajomych z KeepSafe, który zawierał to samo, co ja. U mnie zadziałało, więc miejmy nadzieję, że Tobie też pomoże! Przeczytaj, jeśli jesteś zainteresowany ( Niebezpieczeństwa ładowania natywnych bibliotek na Androida ) lub po prostu użyj

compile 'com.getkeepsafe.relinker:relinker:1.2.3'

i wymień

System.loadLibrary("myLibrary");

z

ReLinker.loadLibrary(context, "mylibrary");
rhysl
źródło
1

Kiedyś miałem dokładnie ten sam problem i ostatecznie został rozwiązany.

Umieściłem wszystkie zależne biblioteki DLL w tym samym folderze, w którym był przechowywany mylib.dll i upewniłem się, że kompilator JAVA może go znaleźć (jeśli w ścieżce kompilacji nie ma mylib.dll, wystąpiłby błąd zgłaszający to podczas kompilacji). Ważną rzeczą na którą musisz zwrócić uwagę jest to, że musisz upewnić się, że wszystkie zależne biblioteki są w tej samej wersji co mylib.dll, na przykład jeśli twój mylib.dll jest wersją wydania, powinieneś również umieścić tam wydanie wszystkich bibliotek zależnych .

Mam nadzieję, że może to pomóc innym, którzy napotkali ten sam problem.

Steven Peng
źródło
1

Miałem ten sam problem i próbowałem wszystkiego, co jest tutaj, aby go naprawić, ale nic nie działało. W moim przypadku używam Cygwin do kompilacji dll. Wygląda na to, że JVM próbuje znaleźć biblioteki DLL JRE w wirtualnej ścieżce Cygwin. Dodałem ścieżkę katalogu wirtualnego Cygwin do bibliotek DLL JRE i teraz działa. Zrobiłem coś takiego:

SET PATH = "/ cygdrive / c / Program Files / Java / jdk1.8.0_45";% PATH%

estebanuri
źródło
1

W mojej sytuacji próbowałem uruchomić usługę internetową java w Tomcat 7 przez złącze w Eclipse. Aplikacja działała dobrze, gdy wdrożyłem plik wojenny w instancji Tomcat 7 na moim laptopie. Aplikacja wymaga sterownika jdbc typu 2 dla „IBM DB2 9.5”. Z jakiegoś dziwnego powodu łącznik w Eclispe nie mógł zobaczyć lub użyć ścieżek w zmiennych środowiskowych IBM DB2, aby dotrzeć do plików dll zainstalowanych na moim laptopie jako klient jcc. W komunikacie o błędzie stwierdzono, że nie można znaleźć pliku dll db2jcct2 lub nie można znaleźć bibliotek zależnych dla tego pliku dll. Ostatecznie usunąłem złącze i odbudowałem je. Wtedy działało poprawnie. Dodam tutaj to rozwiązanie jako dokumentację, ponieważ nie udało mi się znaleźć tego konkretnego rozwiązania nigdzie indziej.

bwfrieds
źródło
0

Stworzenie biblioteki statycznej zadziałało dla mnie, kompilacja przy użyciu g++ -static. Zawiera biblioteki zależne wraz z kompilacją.

Cezar
źródło
0

instalacja pakietu redystrybucyjnego Microsoft Visual C ++ 2010 SP1 Naprawiono to

Sunil Kumar
źródło
0

umieść wymagane biblioteki DLL w folderze i ustaw ścieżkę folderu w zmiennej środowiskowej PATH. upewnij się, że zaktualizowana zmienna PATH środowiska jest odzwierciedlona.

user3122472
źródło
0

Miałem ten sam problem z biblioteką ffmpeg po połączeniu dwóch projektów Androida jako jednego projektu.

Właściwie pojawił się problem z powodu dwóch różnych wersji biblioteki ffmpeg, ale zostały one załadowane do pamięci z tymi samymi nazwami. Jedna biblioteka została umieszczona w JNiLibs, a druga w innej bibliotece używanej jako moduł. Nie byłem w stanie zmodyfikować kodu modułu, ponieważ był on tylko do odczytu, więc zmieniłem nazwę używanego w moim kodzie na ffmpegCamera i załadowałem go do pamięci o tej samej nazwie.

System.loadLibrary("ffmpegCamera");

To rozwiązało problem i teraz obie wersje bibliotek ładują się w pamięci, a także mają oddzielną nazwę i identyfikator procesu.

Mohsin Raza
źródło
0

Dzwoniąc System.loadLibrary() JVM będzie patrzeć na plikjava.library.path Twojej biblioteki natywnej. Jeśli jednak ta biblioteka natywna zadeklaruje jakiekolwiek zależności od innych bibliotek natywnych, system operacyjny będzie miał za zadanie znalezienie tych zależności bibliotek natywnych.

Ponieważ system operacyjny nie ma pojęcia java.library.path, nie zobaczy żadnych katalogów umieszczonych w java.library.path. Zamiast tego przeszuka tylko katalogi w zmiennej środowiskowej PATH systemu operacyjnego. Jest to całkowicie w porządku, jeśli zależność biblioteki natywnej jest natywną biblioteką systemu operacyjnego, ponieważ zostanie znaleziona w PATH. Jeśli jednak zależność biblioteki natywnej jest biblioteką natywną utworzoną przez Ciebie lub kogoś innego, nie zostanie ona znaleziona w PATH, chyba że ją tam umieścisz. To zachowanie jest dziwne, nieoczekiwane i niezbyt dobrze udokumentowane, ale zostało udokumentowane w narzędziu do śledzenia problemów OpenJDK tutaj . Możesz również znaleźć inną odpowiedź StackOverflow wzmacniającą to wyjaśnienie, tutaj .

Masz więc kilka opcji. Możesz albo załadować każdą bibliotekę natywną w prawidłowej kolejności zależności, używając System.loadLibrary()lub zmodyfikować PATH, aby uwzględnić katalogi, w których są przechowywane biblioteki natywne.

Region39
źródło
-2
  1. Przejdź do http://tess4j.sourceforge.net/usage.html i kliknijVisual C++ Redistributable for VS2012
  2. Pobierz go i uruchom VSU_4\vcredist_x64.exelub w VSU_4\vcredist_x84.exezależności od konfiguracji systemu
  3. Umieść swoje dllpliki w libfolderze wraz z innymi bibliotekami (np \lib\win32-x86\your dll files.).
Pratik Varpe
źródło