java.lang.UnsatisfiedLinkError no *****. dll in java.library.path


92

Come posso caricare un file dll personalizzato nella mia applicazione web? Ho provato quanto segue:

  • Ho copiato tutte le DLL richieste nella system32cartella e ho provato a caricarne una nel ServletcostruttoreSystem.loadLibrary
  • DLL richieste copiate in tomcat_home/shared/libetomcat_home/common/lib

Tutte queste DLL si trovano nell'applicazione WEB-INF/libweb

Risposte:


154

Per System.loadLibrary()funzionare, la libreria (su Windows, una DLL) deve essere in una directory da qualche parte sul tuo PATH o su un percorso elencato nella java.library.pathproprietà di sistema (in modo da poter avviare Java comejava -Djava.library.path=/path/to/dir ).

Inoltre, per loadLibrary(), si specifica il nome di base della libreria, senza il .dllalla fine. Quindi, per /path/to/something.dll, useresti solo System.loadLibrary("something").

Devi anche guardare esattamente UnsatisfiedLinkErrorciò che stai ottenendo. Se dice qualcosa come:

Exception in thread "main" java.lang.UnsatisfiedLinkError: no foo in java.library.path

quindi non riesce a trovare la libreria foo (foo.dll) nel tuo PATHo java.library.path. Se dice qualcosa come:

Exception in thread "main" java.lang.UnsatisfiedLinkError: com.example.program.ClassName.foo()V

allora qualcosa non va nella libreria stessa, nel senso che Java non è in grado di mappare una funzione Java nativa nell'applicazione alla sua controparte nativa effettiva.

Per cominciare, metterei un po 'di log intorno alla tua System.loadLibrary()chiamata per vedere se viene eseguita correttamente. Se genera un'eccezione o non si trova in un percorso di codice che viene effettivamente eseguito, otterrai sempre l'ultimo tipo diUnsatisfiedLinkError spiegato sopra.

Come nota a margine, la maggior parte delle persone inserisce le proprie loadLibrary()chiamate in un blocco di inizializzazione statico nella classe con i metodi nativi, per assicurarsi che venga sempre eseguito esattamente una volta:

class Foo {

    static {
        System.loadLibrary('foo');
    }

    public Foo() {
    }

}

1
Inserendo tutte le DLL in System32 e utilizzando System.loadLibrary ("qualcosa") ha funzionato. Prima stavo facendo System.loadLibrary ("something.dll"). Perché non può caricare tutte le DLL da WEB-INF? Immagino che carichi tutti i barattoli per impostazione predefinita. Cosa posso fare per caricare queste DLL direttamente da WEB-INF invece di System32 / specificarle in java.library.path
Ketan Khairnar,

2
+1 per l 'uso "bla" invece di "bla.dll" per il loadLibrary()commento - molto utile quando non hai idea di cosa stai facendo di sbagliato.
MarnixKlooster ReinstateMonica

20
Sul mio sistema (Linux e java7), ho bisogno di un libprefisso. Quindi ha System.loadLibrary("foo")bisogno libfoo.so.
kristianlm

2
Grazie. Ha funzionato per me quando ho aggiornato "PATH" per Windows in modo che contenga una cartella con file * .so.
user613114

15

La modifica della variabile "java.library.path" in fase di esecuzione non è sufficiente perché viene letta una sola volta da JVM. Devi resettarlo come:

System.setProperty("java.library.path", path);
//set sys_paths to null
final Field sysPathsField = ClassLoader.class.getDeclaredField("sys_paths");
sysPathsField.setAccessible(true);
sysPathsField.set(null, null);

Per favore, prendi un bottino a: Modifica del percorso della libreria Java in runtime .


10

La risposta originale di Adam Batkin ti porterà a una soluzione, ma se ridistribuisci la tua webapp (senza riavviare il tuo web container), dovresti incorrere nel seguente errore:

java.lang.UnsatisfiedLinkError: Native Library "foo" already loaded in another classloader
   at java.lang.ClassLoader.loadLibrary0(ClassLoader.java:1715)
   at java.lang.ClassLoader.loadLibrary(ClassLoader.java:1646)
   at java.lang.Runtime.load0(Runtime.java:787)
   at java.lang.System.load(System.java:1022)

Ciò accade perché il ClassLoader che ha caricato originariamente la DLL fa ancora riferimento a questa DLL. Tuttavia, la tua webapp è ora in esecuzione con un nuovo ClassLoader, e poiché la stessa JVM è in esecuzione e una JVM non consente 2 riferimenti alla stessa DLL, non puoi ricaricarla . Pertanto, la tua webapp non può accedere alla DLL esistente e non può caricarne una nuova. Quindi ... sei bloccato.

La documentazione ClassLoader di Tomcat delinea il motivo per cui la tua webapp ricaricata viene eseguita in un nuovo ClassLoader isolato e come puoi aggirare questa limitazione (a un livello molto alto).

La soluzione è estendere un po 'la soluzione di Adam Batkin:

   package awesome;

   public class Foo {

        static {
            System.loadLibrary('foo');
        }

        // required to work with JDK 6 and JDK 7
        public static void main(String[] args) {
        }

    }

Quindi posizionare un vaso contenente SOLO questa classe compilata nella cartella TOMCAT_HOME / lib.

Ora, all'interno della tua webapp, devi solo forzare Tomcat a fare riferimento a questa classe, il che può essere fatto semplicemente come questo:

  Class.forName("awesome.Foo");

Ora la tua DLL dovrebbe essere caricata nel classloader comune e può essere referenziata dalla tua webapp anche dopo essere stata ridistribuita.

Ha senso?

Una copia di riferimento funzionante può essere trovata su google code, static-dll-bootstrapper .


1
Questa risposta è eccellente per i server delle applicazioni e dovrebbe avere una sua domanda in quanto è sprecata su questa domanda.
JoshDM

8

È possibile utilizzare System.load()per fornire un percorso assoluto che è quello che si desidera, piuttosto che un file nella cartella della libreria standard per il rispettivo sistema operativo.

Se desideri applicazioni native già esistenti, usa System.loadLibrary(String filename). Se vuoi fornire il tuo, probabilmente stai meglio con load ().

Dovresti anche essere in grado di usare correttamente loadLibrarycon il java.library.pathset. Vedi l' ClassLoader.javaorigine dell'implementazione che mostra entrambi i percorsi controllati (OpenJDK)


Grazie. L'utilizzo del carico è in realtà molto più semplice e intuitivo IMHO. Impossibile far funzionare loadLibrary, indipendentemente da quello che ho fatto ...
Plankalkül

2
Questa soluzione non funziona per le librerie che caricano le proprie librerie native.
Justin Skiles

7

Nel caso in cui il problema sia che System.loadLibrary non riesce a trovare la DLL in questione, un malinteso comune (rafforzato dal messaggio di errore di Java) è che la proprietà di sistema java.library.path sia la risposta. Se si imposta la proprietà di sistema java.library.path sulla directory in cui si trova la DLL, System.loadLibrary troverà effettivamente la DLL. Tuttavia, se la tua DLL a sua volta dipende da altre DLL, come spesso accade, java.library.path non può essere d'aiuto, perché il caricamento delle DLL dipendenti è gestito interamente dal sistema operativo, che non conosce java.library. sentiero. Pertanto, è quasi sempre meglio bypassare java.library.path e aggiungere semplicemente la directory della DLL a LD_LIBRARY_PATH (Linux), DYLD_LIBRARY_PATH (MacOS) o Path (Windows) prima di avviare la JVM.

(Nota: sto usando il termine "DLL" nel senso generico di DLL o libreria condivisa.)


5

Se devi caricare un file relativo a una directory in cui ti trovi già (come nella directory corrente), ecco una semplice soluzione:

File f;

if (System.getProperty("sun.arch.data.model").equals("32")) {
    // 32-bit JVM
    f = new File("mylibfile32.so");
} else {
    // 64-bit JVM
    f = new File("mylibfile64.so");
}
System.load(f.getAbsolutePath());

4

Per chi cerca java.lang.UnsatisfiedLinkError: no pdf_java in java.library.path

Stavo affrontando la stessa eccezione; Ho provato di tutto e le cose importanti per farlo funzionare sono:

  1. Versione corretta di pdf lib.jar (Nel mio caso era errata la versione jar mantenuta nel runtime del server)
  2. Crea una cartella e mantieni il jar pdflib al suo interno e aggiungi la cartella nella tua variabile PATH

Ha funzionato con Tomcat 6.


3
  1. Se ritieni di aver aggiunto un percorso di lib nativa a %PATH%, prova a eseguire il test con:

    System.out.println(System.getProperty("java.library.path"))

Dovrebbe mostrarti effettivamente se la tua dll è attiva %PATH%

  1. Riavvia IDE Idea, che sembrava funzionare per me dopo aver impostato la variabile env aggiungendola al file %PATH%

2

Povero me ! ho passato un'intera giornata dietro a questo, scrivendolo qui se qualcuno replica questo problema.

Stavo cercando di caricare come suggerito da Adam, ma poi sono stato beccato con l'eccezione AMD64 vs IA 32.Se in ogni caso dopo aver lavorato secondo la procedura dettagliata di Adam (senza dubbio la scelta migliore), prova ad avere una versione a 64 bit dell'ultimo jre. i tuoi JRE E JDK sono a 64 bit e l'hai aggiunto correttamente al tuo classpath.

Il mio esempio funzionante va qui: errore di collegamento insoddisfatto


0

Per Windows ho scoperto che quando ho caricato i filles (chiamate jd2xsx.dll e ftd2xx.dll) nella cartella windowws / system32 questo ha risolto i problemi. Poi ho avuto un problema con il mio più recente fd2xx.dll che aveva a che fare con i parametri, motivo per cui ho dovuto caricare la versione precedente di questo dll. Dovrò individuarlo più tardi.

Nota: jd2xsx.dll chiama ftd2xx.dll quindi la semplice impostazione del percorso per jd2xx.dll potrebbe non funzionare.


0

Sto usando Mac OS X Yosemite e Netbeans 8.02, ho ricevuto lo stesso errore e la semplice soluzione che ho trovato è come sopra, questo è utile quando devi includere la libreria nativa nel progetto. Quindi fai il prossimo per Netbeans:

1.- Right click on the Project
2.- Properties
3.- Click on RUN
4.- VM Options: java -Djava.library.path="your_path"
5.- for example in my case: java -Djava.library.path=</Users/Lexynux/NetBeansProjects/NAO/libs>
6.- Ok

Spero possa essere utile per qualcuno. Il link dove ho trovato la soluzione è qui: java.library.path - Cos'è e come si usa


Ciao Alex, ho una domanda qui, c'è qualche problema se il percorso della libreria include una certa spaziatura nel percorso in questa rigaVM Options: java -Djava.library.path="your_path"
Lokesh Pandey,

Mmm Non sto lavorando con Java nell'ultimo anno ma poiché potrebbero apparire conflitti, consiglio di evitare di aggiungere spazi vuoti nel percorso del file .
alexventuraio

0

Ho avuto lo stesso problema e l'errore era dovuto a una ridenominazione della dll. Potrebbe accadere che anche il nome della libreria sia scritto da qualche parte all'interno della dll. Quando ho rimesso il nome originale sono stato in grado di caricare utilizzandoSystem.loadLibrary


0

È semplice basta scrivere java -XshowSettings: properties sulla riga di comando in Windows e quindi incollare tutti i file nel percorso mostrato da java.library.path.

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.