2012-05-21 22 views
5

Esiste un'istruzione Java indipendente dalla piattaforma per caricare una libreria nativa da una directory diversa da quella in cui si trova il codice sorgente Java? Vorrei usare qualcosa di simile:istruzione portatile per caricare la libreria JNI da una directory diversa utilizzando il relativo percorso?

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

    public static native void print(); 
} 

Il problema è che System.loadLibrary() non supporta separatori di directory nell'argomento percorso. Inoltre, System.load() richiede purtroppo un pathname assoluto, che non solo significa che non posso specificare una directory relativa come sopra (che mi piacerebbe fare), ma richiede anche l'argomento per includere, per esempio, il precedente estensione "lib" e ".so" sul nome della libreria JNI su un sistema Linux.

Esiste un modo standard per gestire questo? Se possibile, vorrei evitare di scrivere una serie di codice Java dipendente dalla piattaforma solo per costruire il nome corretto della libreria JNI.

+0

Non sarebbe più stabile se il percorso fosse relativo ad es. il tuo file .jar piuttosto che la "directory corrente". Questo è destinato a darti problemi a lungo termine se la directory corrente è qualcosa di diverso (ad esempio a causa di un collegamento sul desktop) –

+0

Questo è un buon punto, grazie per averlo indicato. Non so come utilizzare un percorso relativo a un file .jar, ma per evitare di porre una seconda domanda in un commento, mi limiterò a collegarmi ad alcune altre domande StackOverflow che sembrano utili: http: // StackOverflow .com/questions/2837263/how-do-i-get-the-directory-that-the-currently-executing-jar-file-is-in http://stackoverflow.com/questions/5053150/how- to-know-jar-file-directory http://stackoverflow.com/questions/779650/where-on-the-file-system-was-my-java-class-loaded-da –

+0

La prima ricerca (il uno che usa 'getProtectionDomain()') è l'unica risposta corretta a quel problema. –

risposta

13

Credo che stiate cercando System.mapLibraryName, che è il metodo utilizzato in genere dalle implementazioni ClassLoader.findLibrary. Per esempio:

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

Questo userà libHelloWorld.so su Linux e su Windows HelloWorld.dll. Tieni presente che alcuni sistemi operativi supportano più estensioni e mapLibraryName può supportarne solo uno, in base alla progettazione. Quelle di cui sono a conoscenza sono MacOS (.dylib principalmente e .jnilib per legacy) e AIX (.a e .so).

+2

Grazie! Questo è quello che stavo cercando. L'ho appena provato e funziona benissimo. Solo per riferimento di chiunque altro legga questo, System.load() richiede un nome assoluto del percorso, quindi la directory deve essere resa assoluta e una barra finale aggiunta, ad esempio, con il codice: new java.io.File (". ./some_project/"). getCanonicalPath() +"/" –

+1

Ho aggiornato la risposta per includere' getAbsolutePath', grazie. –

+1

+1 mapLibraryName è il pezzo del puzzle di cui non sapevo nulla –

0

Bene, come è stato spiegato chiaramente, non è possibile utilizzare loadLibrary. E così che lascia load. Ma ciò richiede un percorso assoluto. Quindi, espandi il tuo percorso relativo in un percorso assoluto usando le tue funzioni di utilità del percorso file preferite e trasferiscilo a load. Questo può sembrare inopportuno ma è molto più robusto che basarsi sui capricci dei percorsi di ricerca della libreria.

+0

Espandilo in un percorso assoluto come? Ancora più importante, come può essere effettuato il caricamento in modo portatile? La libreria avrebbe tre diversi nomi di file su tre piattaforme diverse: HelloWorld.dll (Windows), libHelloWorld.so (Linux) e libHelloWorld.jnilib (Mac OS X). Quali linee del codice Java selezionerebbero automaticamente il nome appropriato sulla piattaforma appropriata senza che io codifichi con forza un'istruzione switch nel codice Java? –

+0

Bene, un percorso relativo è relativo a qualcosa. Quindi metti quel qualcosa di fronte alla relativa parte e hai il tuo percorso assoluto. Per quanto riguarda l'estensione, non so se c'è qualcosa di integrato, ma dovrebbe essere abbastanza facile da rilevare la piattaforma e passare. –

+0

Il mio obiettivo è avere la possibilità di portare l'applicazione su una nuova piattaforma senza dover ricompilare la parte Java dell'applicazione. Cioè, il codice Java compilato dovrebbe essere portatile.Disporre di un controllo esplicito per vedere su quale sistema operativo è in esecuzione il codice, sfortunatamente non è indipendente dalla piattaforma. –