2012-05-21 3 views
5

Gibt es eine plattformunabhängige Java-Anweisung zum Laden einer nativen Bibliothek aus einem anderen Verzeichnis als der Java-Quellcode? Ich möchte so etwas wie diese verwenden:portable-Anweisung zum Laden der JNI-Bibliothek aus einem anderen Verzeichnis unter Verwendung des relativen Pfadnamens?

public class HelloWorld { 
    static { 
     System.loadLibrary("../some_project/HelloWorld"); 
    } 

    public static native void print(); 
} 

Das Problem ist, dass System.loadLibrary() nicht Verzeichnis-Separatoren im Pfadnamen Argument nicht unterstützt. Außerdem benötigt System.load() leider einen absoluten Pfadnamen, was nicht nur bedeutet, dass ich kein relatives Verzeichnis wie oben angegeben angeben kann (was ich gerne tun würde), sondern es erfordert auch, dass das Argument zum Beispiel das Vorhergehende enthält "lib" und ".so" Erweiterung für den JNI-Bibliotheksnamen auf einem Linux-System.

Gibt es einen Standard-Umgang damit? Wenn möglich, möchte ich vermeiden, eine Menge plattformabhängigen Java-Code zu schreiben, nur um den korrekten JNI-Bibliotheksnamen zu erstellen.

+0

Wäre es nicht stabiler, wenn der Pfad relativ zu z.B. Ihre .jar-Datei und nicht das "aktuelle Verzeichnis". Das wird auf lange Sicht zu Problemen führen, wenn das aktuelle Verzeichnis etwas anderes ist (z. B. wegen einer Verknüpfung auf dem Desktop) –

+0

Das ist ein guter Punkt, danke, dass Sie darauf hingewiesen haben. Ich weiß nicht, wie man einen Pfad relativ zu einer .jar-Datei verwendet, aber um eine zweite Frage in einem Kommentar zu vermeiden, verlinke ich einfach auf einige andere stackoverflow-Fragen, die hilfreich zu sein scheinen: http: // stackoverflow .com/questions/2837263/how-do-ich-bekomme-das-Verzeichnis-das-gerade-ausführende-jar-file-is-in http://StackOverflow.com/Questions/5053150/how- to-know-jar-file-verzeichnis http://stackoverflow.com/questions/779650/where-on-the-file-system-was-my-java-class-loaded-from –

+0

Die erste Frage (die Eine, die 'getProtectionDomain()' verwendet, ist die einzig richtige Antwort auf dieses Problem. –

Antwort

13

Ich glaube, Sie suchen nach System.mapLibraryName, das ist die Methode von ClassLoader.findLibrary Implementierungen typischerweise verwendet. Zum Beispiel:

File lib = new File("../some_project/" + System.mapLibraryName("HelloWorld")); 
System.load(lib.getAbsolutePath()); 

Dies wird libHelloWorld.so auf Linux und HelloWorld.dll unter Windows verwenden. Beachten Sie, dass einige Betriebssysteme mehrere Erweiterungen unterstützen, und mapLibraryName kann nur eines unterstützen. Die mir bekannten sind MacOS (.dylib in erster Linie und .jnilib für Legacy) und AIX (.a und .so).

+2

Danke! Das habe ich gesucht. Ich habe es gerade ausprobiert und es funktioniert super. Nur als Referenz für irgendjemanden, der dies liest, benötigt System.load() einen absoluten Pfadnamen, also muss das Verzeichnis absolut gemacht werden und ein hinterer Schrägstrich hinzugefügt werden, zB mit dem Code: new java.io.File (". ./some_project/"). getCanonicalPath() +"/" –

+1

Ich habe die Antwort aktualisiert, um den' getAbsolutePath' hinzuzufügen, danke. –

+1

+1 mapLibraryName ist das Puzzleteil, von dem ich nichts wusste –

0

Nun, wie Sie klar erklärt haben, können Sie loadLibrary nicht verwenden. Und so dass Blätter load. Aber das erfordert einen absoluten Pfad. Erweitern Sie daher Ihren relativen Pfad mithilfe der von Ihnen bevorzugten Dienstfunktionen für den Dateipfad in einen absoluten Pfad und geben Sie diesen an load weiter. Dies mag unbequem erscheinen, aber es ist viel robuster, als sich auf die Launen der Bibliothekssuchpfade zu verlassen.

+0

Erweitern Sie es auf einen absoluten Pfad wie? Was noch wichtiger ist, wie kann das Laden in einer tragbaren Weise durchgeführt werden? Die Bibliothek hätte drei verschiedene Dateinamen auf drei verschiedenen Plattformen: HelloWorld.dll (Windows), libHelloWorld.so (Linux) und libHelloWorld.jnilib (Mac OS X). Welche Zeile (n) von Java-Code würde automatisch den passenden Namen auf der entsprechenden Plattform auswählen, ohne dass ich eine switch-Anweisung in den Java-Code fest codiere? –

+0

Nun, ein relativer Pfad ist relativ zu etwas. Also stell das vor den relativen Teil und du hast deinen absoluten Weg. Was die Erweiterung betrifft, weiß ich nicht, ob etwas eingebaut ist, aber es sollte einfach genug sein, Plattform und Switch zu erkennen. –

+0

Mein Ziel ist es, die Anwendung auf eine neue Plattform portieren zu können, ohne den Java-Teil der Anwendung neu kompilieren zu müssen. Das heißt, der kompilierte Java-Code sollte tragbar sein.Eine explizite Überprüfung, um festzustellen, auf welchem ​​Betriebssystem der Code läuft, ist leider nicht plattformunabhängig. –

Verwandte Themen