Come risolvere un errore UnsatisfiedLinkError (impossibile trovare le librerie dipendenti) in un progetto JNI


86

Sto lavorando a un progetto Java che utilizza JNI. JNI chiama una libreria personalizzata che ho scritto io stesso, diciamo mylib.dll, e che dipende da una libreria di terze parti, libsndfile-1.dll.

Quando eseguo il mio programma si blocca con

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

Ho cercato in questo sito (e altri) e ho provato una serie di correzioni:

  1. Ho eseguito il walker delle dipendenze. DW ha fornito un paio di avvertimenti - che due librerie richieste da libsndfile, MPR.DLL e SHLWAPI.DLL, avevano "importazioni non risolte" - ma la FAQ DW ha detto che questi avvertimenti potevano essere tranquillamente ignorati.

  2. Ho corretto i nomi dei metodi in mylib.dll, come suggerito qui . I nomi dei metodi erano stati in qualche modo alterati dal compilatore, ma ho aggiunto i flag del linker ei nomi dei metodi dll ora corrispondono esattamente a quelli nel mio file di intestazione jni.

  3. Metto tutte queste DLL nella stessa directory, la stessa directory del .jar che le chiama, per assicurarmi che siano sul PERCORSO corretto.

Niente da fare.

Qualcuno ha idea di cosa stia succedendo?

Sto sviluppando in Visual Studio 2010 su un MacBook pro (tramite Parallels). Sto eseguendo i test in Windows XP su un laptop toshiba.


1
hai impostato -Djava.library.path?
Jochen Bedersdorfer

Non l'ho fatto, in realtà, perché non sto avviando il programma dalla riga di comando. Sto scrivendo una libreria per Processing (processing.org) e Processing è responsabile del lancio del mio codice. Tuttavia, ho controllato il percorso della libreria Java in fase di esecuzione e la cartella contenente le mie DLL si trova su di essa.
dB "

Come ho detto, tutte le DLL si trovano nella stessa cartella, accanto al mio file .jar. Quindi non credo che il problema sia che non sono sul sentiero. Ma grazie comunque.
dB "

7
Su Windows abbiamo dovuto mettere i file .dll nella directory [JRE] \ bin (lo stesso posto in cui si trovano java.exe, ecc.) Per fare in modo che Java li vedesse automaticamente senza dover utilizzare le opzioni della riga di comando o le variabili d'ambiente.
QuantumMechanic

4
Hmm ... ok, ho provato a mettere tutti i miei file .dll in [JRE] \ bin. Funziona!
dB '23

Risposte:


52

Sono abbastanza sicuro che il percorso di classe e il percorso di ricerca della libreria condivisa abbiano poco a che fare l'uno con l'altro. Secondo The JNI Book (che certamente è vecchio), su Windows se non si utilizza la java.library.pathproprietà di sistema, la DLL deve essere nella directory di lavoro corrente o in una directory elencata nella PATHvariabile di ambiente Windows .


Aggiornare:

Sembra che Oracle abbia rimosso il PDF dal suo sito web. Ho aggiornato il collegamento sopra per indicare un'istanza del PDF che vive presso l'Università del Texas - Arlington.

Inoltre, è anche possibile leggere la versione HTML di Oracle della specifica JNI . Si trova nella sezione Java 8 del sito Web Java e quindi si spera che rimarrà in giro per un po '.


Aggiornamento 2:

Almeno in Java 8 (non ho controllato le versioni precedenti) puoi fare:

java -XshowSettings:properties -version

per trovare il percorso di ricerca della libreria condivisa. Cerca il valore della java.library.pathproprietà in quell'output.


2
Sì, CLASSPATHnon viene utilizzato affatto. Non sono nemmeno sicuro che cwdsia usato. java.library.patho semplicemente PATHfunzionerà. @dB ', il posto dove li hai ora è sbagliato .
Ernest Friedman-Hill

Grazie mille ragazzi! Penso che parte del problema qui fosse una confusione da parte mia tra la variabile d'ambiente PATH di Windows, java.library.path e java CLASSPATH. Ora tutto ha più senso.
dB '23

Per favore, puoi spiegare come hai superato questo problema?
SL_User

5
@SL_User Penso che se aggiungi la directory in cui si trovano le librerie alla variabile di ambiente "path" e riavvia il prompt dei comandi o il terminale dovrebbe risolverlo. Java cerca i jar in classpath e le librerie in path.
xxjjnn

1
Sulla base di questa risposta, sembra che il comando di Update 2 è disponibile da almeno Java 7: stackoverflow.com/a/8472139/901641
ArtOfWarfare

18

Voglio informare questo caso interessante, dopo aver provato tutto il metodo sopra, l'errore è ancora lì. La cosa strana è che funziona su un computer Windows 7, ma su Windows XP non lo è. Quindi uso il walker delle dipendenze e ho scoperto che su Windows XP non esiste il runtime VC ++ come requisito della dll. Dopo aver installato il pacchetto Runtime VC ++ qui funziona come un fascino. La cosa che mi ha disturbato è che continua a dire Impossibile trovare librerie dipendenti, mentre intuitivamente la DLL dipendente da JNI è presente, tuttavia alla fine risulta che la DLL dipendente da JNI richiede un altro DL dipendente. Spero che possa aiutare.


4
Il messaggio è corretto anche se in questo caso fuorviante. Avevo entrambi i runtime VC ++ mancanti sulla scatola di prova e la libreria compilata in modalità debug (a seconda dei runtime di debug non ridistribuibili). Dependency Walker è stato di grande aiuto per capirlo.
Johnny Baloney,

ha avuto lo stesso problema utilizzando jnetpcap-library. la dipendenza winpcap non era più installata sulla macchina e il messaggio di eccezione era fuorviante
BlackFlag

Penso che questo potrebbe essere il mio caso.
I.Tyger

In questi giorni, il camminatore delle dipendenze sta diventando piuttosto "lungo nel dente". Non è stato possibile aprire una dll di Windows 10/64 bit recente, quindi non ho ancora idea di quale libreria manchi ... Whee.
Mark Storer


5

Verifica che il percorso della tua libreria sia corretto o meno. Naturalmente, puoi utilizzare il seguente codice per controllare il percorso del percorso della tua libreria: System.out.println(System.getProperty("java.library.path"));

È possibile nominare java.library.path quando si avvia un'applicazione Java:

java -Djava.library.path=path ...

4

Se carichi una versione a 32 bit della tua dll con un JRE a 64 bit potresti avere questo problema. Questo è stato il mio caso.


Questo è molto probabilmente anche il mio caso; se qualcuno è a conoscenza di soluzioni alternative note, sarei interessato; tranne il caricamento di una versione a 64 bit, poiché in questo caso il processo non è una dll ma chromedriver.exe, il driver Selenium per Chrome, che per quanto ne so è disponibile solo nella versione a 32 bit.
SantiBailors

4

Ha avuto lo stesso problema con la macchina XP durante l'installazione javacve opencvin combinazione con Eclipse. Si è scoperto che mi mancavano i seguenti file:

  • msvcp100.dll
  • msvcr100.dll

Una volta installati, il progetto è stato compilato ed è stato eseguito correttamente.


Ho il problema simile che scompare dopo l'installazione di "Microsoft Visual C ++ 2010 SP1 Redistributable Package (x86)"
Kirill Mikhailov

2
  • Risposta breve: per l'errore "impossibile trovare la libreria dipendente", controlla il tuo $ PATH (corrisponde al punto 3 di seguito)
  • Risposta lunga:
    1. Pure java world: jvm usa "Classpath" per trovare i file di classe
    2. JNI world (java / native boundary): jvm utilizza "java.library.path" (il cui valore predefinito è $ PATH) per trovare le dll
    3. puro mondo nativo: il codice nativo utilizza $ PATH per caricare altre dll

2

Ho trovato un ottimo articolo di alcuni amici di Keepsafe che ha ripetuto la stessa cosa che ho fatto io. Ha funzionato per me, quindi spero che aiuti anche te! Dai una lettura se sei interessato ( I pericoli del caricamento di librerie native su Android ) o usa semplicemente

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

e sostituire

System.loadLibrary("myLibrary");

con

ReLinker.loadLibrary(context, "mylibrary");

1

Avevo esattamente lo stesso problema e alla fine è stato risolto.

Metto tutte le DLL dipendenti nella stessa cartella in cui è stato memorizzato mylib.dll e mi assicuro che il compilatore JAVA possa trovarlo (se non c'è mylib.dll nel percorso di compilazione, ci sarebbe un errore che lo segnala durante la compilazione). La cosa importante che devi notare è che devi assicurarti che tutte le librerie dipendenti siano della stessa versione di mylib.dll, ad esempio se la tua mylib.dll è la versione di rilascio, dovresti anche inserire la versione di rilascio di tutte le sue librerie dipendenti lì .

Spero che questo possa aiutare altri che hanno riscontrato lo stesso problema.


1

Ho avuto lo stesso problema e ho provato tutto ciò che è pubblicato qui per risolverlo, ma nessuno ha funzionato per me. Nel mio caso sto usando Cygwin per compilare la dll. Sembra che JVM cerchi di trovare le DLL JRE nel percorso virtuale di Cygwin. Ho aggiunto il percorso della directory virtuale di Cygwin alle DLL di JRE e ora funziona. Ho fatto qualcosa come:

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


1

Nella mia situazione, stavo cercando di eseguire un servizio Web Java in Tomcat 7 tramite un connettore in Eclipse. L'app ha funzionato bene quando ho distribuito il file war su un'istanza di Tomcat 7 sul mio laptop. L'app richiede un driver jdbc di tipo 2 per "IBM DB2 9.5". Per qualche strana ragione il connettore in Eclispe non poteva vedere o utilizzare i percorsi nelle variabili d'ambiente IBM DB2, per raggiungere i file dll installati sul mio laptop come client jcc. Il messaggio di errore indicava che non era riuscito a trovare il file dll db2jcct2 o non era riuscito a trovare le librerie dipendenti per quel file dll. Alla fine, ho eliminato il connettore e l'ho ricostruito. Quindi ha funzionato correttamente. Sto aggiungendo questa soluzione qui come documentazione, perché non sono riuscito a trovare questa soluzione specifica altrove.


0

La creazione della libreria statica ha funzionato per me, la compilazione utilizzando g++ -static. Raggruppa le librerie dipendenti insieme alla build.


0

installazione di Microsoft Visual C ++ 2010 SP1 Redistributable Risolto


0

posizionare le DLL richieste nella cartella e impostare il percorso della cartella nella variabile di ambiente PATH. assicurati che la variabile PATH dell'ambiente aggiornata sia riflessa.


0

Stavo affrontando lo stesso problema con la libreria ffmpeg dopo aver unito due progetti Android come un unico progetto.

In realtà il problema stava arrivando a causa di due diverse versioni della libreria ffmpeg ma erano caricate con gli stessi nomi in memoria. Una libreria è stata collocata in JNiLibs mentre l'altra era all'interno di un'altra libreria utilizzata come modulo. Non sono stato in grado di modificare il codice del modulo poiché era di sola lettura, quindi ho rinominato quello utilizzato nel mio codice in ffmpegCamera e l' ho caricato in memoria con lo stesso nome.

System.loadLibrary("ffmpegCamera");

Questo ha risolto il problema e ora entrambe le versioni delle librerie vengono caricate bene come nome separato e ID processo in memoria.


0

Durante la chiamata System.loadLibrary(), la JVM guarderà sujava.library.path tua libreria nativa. Tuttavia, se quella libreria nativa dichiara delle dipendenze da altre librerie native, il sistema operativo avrà il compito di trovare quelle dipendenze della libreria nativa.

Dal momento che il sistema operativo non ha il concetto di java.library.path, non vedrà alcuna directory inserita in java.library.path. Invece, cercherà solo nelle directory sulla variabile d'ambiente PATH del sistema operativo. Questo va benissimo se la dipendenza della libreria nativa è una libreria nativa del sistema operativo perché si troverà nel PATH. Tuttavia, se la dipendenza della libreria nativa è una libreria nativa creata dall'utente o da qualcun altro, non verrà trovata nel PERCORSO a meno che non la si posizioni lì. Questo comportamento è strano, inaspettato e non ben documentato, ma è documentato nel tracciatore di problemi di OpenJDK qui . Puoi anche trovare un'altra risposta StackOverflow che rafforza questa spiegazione, qui .

Quindi, hai un paio di opzioni. È possibile caricare ciascuna libreria nativa nell'ordine di dipendenza corretto utilizzando System.loadLibrary()oppure modificare il PERCORSO per includere le directory in cui sono archiviate le librerie native.


-2
  1. Vai a http://tess4j.sourceforge.net/usage.html e fai clic suVisual C++ Redistributable for VS2012
  2. Scaricalo ed eseguilo VSU_4\vcredist_x64.exeo in VSU_4\vcredist_x84.exebase alla configurazione del tuo sistema
  3. Metti i tuoi dllfile all'interno della libcartella, insieme alle altre tue librerie (ad esempio \lib\win32-x86\your dll files).
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.