So beheben Sie einen UnsatisfiedLinkError (abhängige Bibliotheken können nicht gefunden werden) in einem JNI-Projekt

85

Ich arbeite an einem Java-Projekt, das das JNI verwendet. Das JNI ruft eine benutzerdefinierte Bibliothek auf, die ich selbst geschrieben habe, sagen wir mylib.dll, und das hängt von einer Bibliothek eines Drittanbieters ab, libsndfile-1.dll.

Wenn ich mein Programm starte, stürzt es mit ab

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

Ich habe diese Site (und andere) durchsucht und eine Reihe von Korrekturen versucht:

  1. Ich lief Dependency Walker. DW gab einige Warnungen aus - dass zwei von libsndfile benötigte Bibliotheken, MPR.DLL und SHLWAPI.DLL, "ungelöste Importe" hatten -, aber die DW-FAQ besagten, dass diese Warnungen sicher ignoriert werden könnten.

  2. Ich habe die Methodennamen in mylib.dll korrigiert, wie hier vorgeschlagen . Die Methodennamen wurden vom Compiler irgendwie entstellt, aber ich habe Linker-Flags hinzugefügt und die Namen der DLL-Methoden stimmen jetzt genau mit denen in meiner JNI-Header-Datei überein.

  3. Ich habe alle diese DLLs in dasselbe Verzeichnis gestellt - dasselbe Verzeichnis wie die .jar, die sie aufruft -, um sicherzustellen, dass sie sich auf dem richtigen Pfad befinden.

Kein Würfel.

Hat jemand eine Idee was los ist?

Ich mache meine Entwicklung in Visual Studio 2010 auf einem MacBook Pro (über Parallels). Ich teste in Windows XP auf einem Toshiba-Laptop.

dB '
quelle
1
Haben Sie -Djava.library.path festgelegt?
Jochen Bedersdorfer
Ich habe es eigentlich nicht getan, weil ich das Programm nicht über die Befehlszeile starte. Ich schreibe eine Bibliothek für Processing (process.org) und Processing ist für das Starten meines Codes verantwortlich. Ich habe jedoch den Java-Bibliothekspfad zur Laufzeit überprüft, und der Ordner mit meinen DLLs befindet sich darauf.
dB '23.
Wie gesagt, alle DLLs befinden sich im selben Ordner neben meiner JAR-Datei. Ich glaube nicht, dass das Problem darin besteht, dass sie nicht auf dem Weg sind. Danke trotzdem.
dB '23.
7
Unter Windows mussten wir DLL-Dateien im Verzeichnis [JRE] \ bin ablegen (an derselben Stelle, an der sich java.exe usw. befinden), damit Java sie automatisch anzeigt, ohne sich mit Befehlszeilenoptionen oder Umgebungsvariablen herumschlagen zu müssen.
QuantumMechanic
4
Hmm ... ok, ich habe versucht, alle meine DLLs in [JRE] \ bin abzulegen. Das funktioniert!
dB '23.

Antworten:

52

Ich bin mir ziemlich sicher, dass der Klassenpfad und der Suchpfad für gemeinsam genutzte Bibliotheken wenig miteinander zu tun haben. Laut The JNI Book (das zugegebenermaßen alt ist) muss sich java.library.pathdie DLL unter Windows, wenn Sie die Systemeigenschaft nicht verwenden , im aktuellen Arbeitsverzeichnis oder in einem Verzeichnis befinden, das in der Windows- PATHUmgebungsvariablen aufgeführt ist.


Aktualisieren:

Anscheinend hat Oracle das PDF von seiner Website entfernt. Ich habe den obigen Link aktualisiert, um auf eine Instanz des PDF zu verweisen, das an der University of Texas - Arlington lebt.

Sie können auch die HTML-Version der JNI-Spezifikation von Oracle lesen . Das lebt im Java 8-Bereich der Java-Website und wird es hoffentlich noch eine Weile geben.


Update 2:

Zumindest in Java 8 (ich habe frühere Versionen nicht überprüft) können Sie Folgendes tun:

java -XshowSettings:properties -version

um den Suchpfad für die gemeinsam genutzte Bibliothek zu finden. Suchen Sie java.library.pathin dieser Ausgabe nach dem Wert der Eigenschaft.

QuantumMechanic
quelle
2
Ja, CLASSPATHwird überhaupt nicht verwendet. Ich bin mir auch nicht sicher, ob das cwdüberhaupt verwendet wird. java.library.pathoder wird einfach PATHfunktionieren. @dB ', der Ort, an dem du sie jetzt hast, ist falsch .
Ernest Friedman-Hill
Vielen Dank Jungs! Ich denke, ein Teil des Problems hier war eine Verwechslung zwischen der Windows PATH-Umgebungsvariablen java.library.path und dem Java CLASSPATH. Jetzt macht alles mehr Sinn.
dB '23.
Können Sie bitte erklären, wie Sie dieses Problem überwunden haben?
SL_User
5
@SL_User Ich denke, wenn Sie das Verzeichnis, in dem sich die Bibliotheken befinden, zur Umgebungsvariablen "path" hinzufügen und die Eingabeaufforderung oder das Terminal neu starten, sollte dies behoben werden. Java sucht unter Klassenpfad nach Jars und unter Pfad nach Bibliotheken.
xxjjnn
1
Basierend auf dieser Antwort sieht es so aus, als ob dieser Befehl für Update 2 seit mindestens Java 7 verfügbar ist: stackoverflow.com/a/8472139/901641
ArtOfWarfare
18

Ich möchte diesen interessanten Fall informieren, nachdem alle oben genannten Methoden ausprobiert wurden, ist der Fehler immer noch da. Das Seltsame ist, dass es auf einem Windows 7-Computer funktioniert, unter Windows XP jedoch nicht. Dann benutze ich Dependency Walker und habe unter Windows XP festgestellt, dass es keine VC ++ Runtime als DLL-Anforderung gibt. Nach der Installation von VC ++ Runtime - Paket hier funktioniert es wie ein Zauber. Das, was mich gestört hat, ist, dass es immer wieder sagt, dass abhängige Bibliotheken nicht gefunden werden können, während intuitiv die JNI-abhängige DLL vorhanden ist. Es stellt sich jedoch schließlich heraus, dass die JNI-abhängige DLL eine andere abhängige DLL erfordert. Ich hoffe das hilft.

longbkit
quelle
4
Die Nachricht ist korrekt, wenn auch in diesem Fall irreführend. Ich hatte sowohl VC ++ - Laufzeiten auf der Testbox als auch die im Debug-Modus kompilierte Bibliothek (abhängig von nicht weiterverteilbaren Debug-Laufzeiten). Dependency Walker war eine große Hilfe, um dies herauszufinden.
Johnny Baloney
hatte das gleiche Problem mit jnetpcap-Bibliothek. Die Abhängigkeit Winpcap wurde nicht mehr auf dem Computer installiert und die Ausnahmemeldung war irreführend
BlackFlag
Ich denke, das könnte mein Fall sein.
I. Tyger
Heutzutage wird der Abhängigkeitsläufer ziemlich "lang im Zahn". Eine aktuelle Windows 10/64-Bit-DLL konnte überhaupt nicht geöffnet werden, daher habe ich immer noch keine Ahnung, welche Bibliothek fehlt ... Whee.
Mark Storer
5

Bitte überprüfen Sie, ob Ihr Bibliothekspfad richtig ist oder nicht. Natürlich können Sie folgenden Code verwenden, um den Pfad Ihres Bibliothekspfads zu überprüfen: System.out.println(System.getProperty("java.library.path"));

Sie können den Pfad java.library.path beim Starten einer Java-Anwendung festlegen :

java -Djava.library.path=path ...
caopeng
quelle
4

Wenn Sie eine 32-Bit-Version Ihrer DLL mit einer 64-Bit-JRE laden, kann dieses Problem auftreten. Das war mein Fall.

EFalco
quelle
Dies ist höchstwahrscheinlich auch mein Fall; Wenn jemand bekannte Problemumgehungen kennt, wäre ich interessiert. außer das Laden einer 64-Bit-Version, da in diesem Fall der Prozess keine DLL ist, sondern chromedriver.exeder Selenium-Treiber für Chrome, der, soweit ich das beurteilen kann, nur in der 32-Bit-Version verfügbar ist.
SantiBailors
4

Hatte bei der Installation javacvund opencvin Kombination mit Eclipse ein identisches Problem mit einem XP-Computer . Es stellte sich heraus, dass mir folgende Dateien fehlten:

  • msvcp100.dll
  • msvcr100.dll

Sobald diese installiert waren, wurde das Projekt kompiliert und lief OK.

Rob van Riswick
quelle
Ich habe das ähnliche Problem, das nach der Installation von "Microsoft Visual C ++ 2010 SP1 Redistributable Package (x86)" verschwindet
Kirill Mikhailov
2
  • Kurze Antwort: Wenn der Fehler "Abhängige Bibliothek kann nicht gefunden werden" angezeigt wird, überprüfen Sie Ihren $ PATH (entspricht dem Punkt 3 unten).
  • Lange Antwort:
    1. Reine Java-Welt: jvm verwendet "Klassenpfad", um Klassendateien zu finden
    2. JNI-Welt (Java / native Grenze): jvm verwendet "java.library.path" (standardmäßig $ PATH), um DLLs zu finden
    3. reine native Welt: Der native Code verwendet $ PATH, um andere DLLs zu laden
user2038596
quelle
2

Ich habe einen großartigen Artikel von einigen Freunden bei keepsafe gefunden, der genau das durchgemacht hat, was ich getan habe. Es hat bei mir funktioniert, also hilft es dir hoffentlich auch! Lesen Sie, wenn Sie interessiert sind ( Die Gefahren beim Laden nativer Bibliotheken auf Android ) oder verwenden Sie es einfach

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

und ersetzen

System.loadLibrary("myLibrary");

mit

ReLinker.loadLibrary(context, "mylibrary");
Rhysl
quelle
1

Früher hatte ich genau das gleiche Problem und schließlich wurde es gelöst.

Ich habe alle abhängigen DLLs in demselben Ordner abgelegt, in dem mylib.dll gespeichert war, und habe sichergestellt, dass der JAVA-Compiler sie finden kann (wenn sich keine mylib.dll im Kompilierungspfad befindet, wird beim Kompilieren ein Fehler gemeldet). Das Wichtigste, was Sie beachten müssen, ist, dass Sie sicherstellen müssen, dass alle abhängigen Bibliotheken dieselbe Version wie mylib.dll haben. Wenn Ihre mylib.dll beispielsweise eine Release-Version ist, sollten Sie dort auch die Release-Version aller abhängigen Bibliotheken ablegen .

Hoffe, dies könnte anderen helfen, die auf das gleiche Problem gestoßen sind.

Steven Peng
quelle
1

Ich hatte das gleiche Problem und habe alles versucht, was hier veröffentlicht ist, um es zu beheben, aber keines hat bei mir funktioniert. In meinem Fall verwende ich Cygwin, um die DLL zu kompilieren. Es scheint, dass JVM versucht, die JRE-DLLs im virtuellen Cygwin-Pfad zu finden. Ich habe den virtuellen Verzeichnispfad des Cygwin zu den DLLs von JRE hinzugefügt und es funktioniert jetzt. Ich habe so etwas gemacht wie:

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

Estebanuri
quelle
1

In meiner Situation habe ich versucht, einen Java-Webdienst in Tomcat 7 über einen Connector in Eclipse auszuführen. Die App lief gut, als ich die Kriegsdatei auf einer Instanz von Tomcat 7 auf meinem Laptop bereitstellte. Die App benötigt einen JDBC-Typ-2-Treiber für "IBM DB2 9.5". Aus irgendeinem Grund konnte der Connector in Eclispe die Pfade in den IBM DB2-Umgebungsvariablen nicht sehen oder verwenden, um die auf meinem Laptop als jcc-Client installierten DLL-Dateien zu erreichen. In der Fehlermeldung wurde entweder angegeben, dass die DLL-Datei db2jcct2 nicht gefunden werden konnte, oder dass die abhängigen Bibliotheken für diese DLL-Datei nicht gefunden wurden. Letztendlich habe ich den Connector gelöscht und neu erstellt. Dann hat es richtig funktioniert. Ich füge diese Lösung hier als Dokumentation hinzu, da ich diese spezielle Lösung nirgendwo anders gefunden habe.

bwfrieds
quelle
0

Das Erstellen einer statischen Bibliothek hat bei mir funktioniert und das Kompilieren mit g++ -static. Es bündelt die abhängigen Bibliotheken zusammen mit dem Build.

Caesar
quelle
0

Installation von Microsoft Visual C ++ 2010 SP1 Redistributable Es wurde behoben

Sunil Kumar
quelle
0

Platzieren Sie die erforderlichen DLLs im Ordner und legen Sie den Ordnerpfad in der Umgebungsvariablen PATH fest. Stellen Sie sicher, dass die aktualisierte Umgebungs-PATH-Variable wiedergegeben wird.

user3122472
quelle
0

Ich hatte das gleiche Problem mit der ffmpeg-Bibliothek, nachdem ich zwei Android-Projekte zu einem Projekt zusammengeführt hatte.

Das eigentliche Problem trat aufgrund von zwei verschiedenen Versionen der ffmpeg-Bibliothek auf, die jedoch mit denselben Namen im Speicher geladen wurden. Eine Bibliothek wurde in JNiLibs abgelegt, während sich die andere in einer anderen Bibliothek befand, die als Modul verwendet wurde. Ich konnte den Code des Moduls nicht ändern, da er schreibgeschützt war. Daher habe ich den in meinem eigenen Code verwendeten in ffmpegCamera umbenannt und ihn mit demselben Namen in den Speicher geladen.

System.loadLibrary("ffmpegCamera");

Dies hat das Problem behoben und jetzt werden beide Versionen von Bibliotheken sowie separate Namen und Prozess-IDs im Speicher geladen.

Mohsin Raza
quelle
-2
  1. Gehen Sie zu http://tess4j.sourceforge.net/usage.html und klicken Sie aufVisual C++ Redistributable for VS2012
  2. Laden Sie es herunter und führen Sie es aus VSU_4\vcredist_x64.exeoder VSU_4\vcredist_x84.exeabhängig von Ihrer Systemkonfiguration
  3. Legen Sie Ihre dllDateien libzusammen mit Ihren anderen Bibliotheken (z \lib\win32-x86\your dll files. B. ) in den Ordner .
Pratik Varpe
quelle