Dependent native libraries in Java


#1

Java sucht native dependent Libraries immer im Ordner in dem die jar liegt bzw. im jeweiligen Systemverzeichnis.
Sprich ich kann zwar eine native library aus einem anderen Verzeichnis laden, aber die anderen native libraries im selben Ordner findet er dann nicht, weil er die dependencies der library nicht im selben Verzeichnis sucht.

Ist natürlich blöd, weil ich muss jetzt die 105 libraries in mein Projektroot legen (IntelliJ) bzw. in das selbe Verzeichnis wie die jar packen. Gibt es da eine schönere Variante? Selbst wenn ich
“-Djava.library.path=./native”
setze. Findet er immer nur die erste. Es macht wirklich keinen Sinn 35 mal System.loadLibrary() in der richtigen Reihenfolge zu schreiben, insbesondere weil sich das jederzeit ändern kann.


#2

Schwierig, sowas remote zu “debuggen”. Man könnte meinen, dass er mit java.library.path alles finden kann, was in diesem Verzeichnis liegt. Aber ja: Sobald er eine native lib lädt, schlägt für das Laden der Dependencies dieser (native) Lib eben der “systeminterne” Lademechanismus zu. In einer ähnlichen Situation hatte ich dann die pragmatische Lösung gewählt, und einfach alle DLLs neben die JAR gelegt - ja, nicht schön, aber “lief” :roll_eyes:

Sind das alles selbstcompilierte libs? (Vermutlich nicht, aber wenn, dann könnte man die vermutlich schon native-seitig in eine 100MB große lib zusammenwursten… )


#3

Java sucht native Libraries immer im java.library.path. Wenn man den so, wie du, ohne die Standardeinträge setzt, dann geschehen solche unerwarteten Dinge. Man kann “-Djava.library.path” mit dem Defaultpath (%PATH% unter Windows) + “;./native” aufrufen oder das Verzeichnis relativ zum Jar-Archiv programmtechnisch ermitteln und der Systemvariable “java.library.path” zur Laufzeit hinzufügen. Wichtig ist, dass hinzugefügt und nicht überschrieben wird.


#4

Das funktioniert nicht. “java.library.path” kann zur Laufzeit nicht mehr geändert werden. Selbst wenn ich ./native nur ‘hinzufüge’ in der Kommandozeile, sucht er die Dependencies der native Dependency trotzdem nicht in diesem Pfad. Ändert also erwartungsgemäß nichts, da er die erste native Dependency auch vorher bereits gefunden hatte.

Das hatte ich so nicht bedacht, aber macht schon Sinn. Die JVM wird wohl nicht mehr viel Kontrolle über den Folgelademechanismus haben. Nach exzessivem Googlen scheint das beabsichtigtes Verhalten zu sein. Manuelles laden der Einzel-Bibliotheken die einzige Möglichkeit um das zu umgehen.

Schade. Danke.


#5

Den Pfad, so wie Spacerat vorgeschlagen hat, mit %PATH% zu setzen, könnte ja eine Option sein - hilft aber wohl nicht, wenn die Libs nur lokal liegen. Sollte es dann aber nicht reichen, das Verzeichnis mit diesen Libs eben zum PATH bzw. LD_LIBRARY_PATH hinzuzufügen…?


#6

Nein,

was ich jetzt verstanden habe:

  • TMII läd eine native.dll - lässt sich über oben genannte Techniken in Verzeichnisse schieben und hinzufügen
  • native.dll läd eine weitere.dll nach - hier schlägt der Algo des BS zu und TMII kann ihn nicht beeinflussen

wenn dem so ist - dann hilft nur noch das BS

hand, mogel


#7

Also insgesamt sollte die Kommandozeile (bzw der Parameter) so aussehen:

Windows:
  -Djava_library_path="%PATH%;.\native"

Linux/Unix
  -Djava_library_path=$PATH:./native"

Den Pfad zur Laufzeit zu ändern sollte auch funktionieren, zumal LWJGL einst davon gebrauch machte, woher ich mir die Technik auch abgeschaut hatte. Ist jedoch nicht ganz so trivial, wenn man Installation und Anwendung Pfadunabhängig machen will - dann muss man den Pfad der Jar-Datei ermitteln, in welchem die Main-Klasse liegt. Unter Linux kommt man da ganz schnell an die Grenze “Sandbox”… über den so ermittelten Pfad kommt man trotz Userrechte ohne Tricks nicht hinaus - evtl hilft es dann schon, “./” wegzulassen.