Cómo corregir un UnsatisfiedLinkError (no se pueden encontrar bibliotecas dependientes) en un proyecto JNI

85

Estoy trabajando en un proyecto de Java que usa JNI. El JNI llama a una biblioteca personalizada que yo mismo escribí, digamos mylib.dll, y eso depende de una biblioteca de terceros, libsndfile-1.dll.

Cuando ejecuto mi programa, se bloquea

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

Busqué en este sitio (y en otros) y probé varias correcciones:

  1. Ejecuté el andador de la dependencia. DW dio un par de advertencias - que dos bibliotecas requeridas por libsndfile, MPR.DLL y SHLWAPI.DLL, tenían "importaciones no resueltas" - pero las preguntas frecuentes de DW dijeron que estas advertencias podían ignorarse sin peligro.

  2. Arreglé los nombres de los métodos en mylib.dll, como se sugiere aquí . El compilador había alterado los nombres de los métodos de alguna manera, pero agregué indicadores del enlazador y los nombres de los métodos dll ahora coinciden exactamente con los de mi archivo de encabezado jni.

  3. Pongo todas estas DLL en el mismo directorio, el mismo directorio que el .jar que las llama, para asegurarme de que estén en la RUTA correcta.

No dados.

¿Alguien tiene alguna idea de lo que está pasando?

Estoy haciendo mi desarrollo en Visual Studio 2010 en una MacBook pro (a través de Parallels). Estoy haciendo mis pruebas en Windows XP en una computadora portátil Toshiba.

dB '
fuente
1
¿Ha configurado -Djava.library.path?
Jochen Bedersdorfer
En realidad, no lo he hecho porque no estoy iniciando el programa desde la línea de comandos. Estoy escribiendo una biblioteca para Processing (processing.org) y Processing es responsable de lanzar mi código. Sin embargo, he comprobado la ruta de la biblioteca de Java en tiempo de ejecución y la carpeta que contiene mis DLL está en ella.
dB '23 de
Como dije, todas las DLL están en la misma carpeta, junto a mi archivo .jar. Así que no creo que el problema sea que no estén en el camino. Pero gracias de todos modos.
dB '23 de
7
En Windows, tuvimos que poner archivos .dll en el directorio [JRE] \ bin (el mismo lugar donde están java.exe, etc.) para que Java los vea automáticamente sin tener que jugar con opciones de línea de comandos o variables de entorno.
QuantumMechanic
4
Hmm ... ok, intenté poner todos mis .dlls en [JRE] \ bin. ¡Esto funciona!
dB '23 de

Respuestas:

52

Estoy bastante seguro de que la ruta de clase y la ruta de búsqueda de la biblioteca compartida tienen poco que ver entre sí. Según The JNI Book (que ciertamente es antiguo), en Windows, si no usa la java.library.pathpropiedad del sistema, la DLL debe estar en el directorio de trabajo actual o en un directorio listado en la PATHvariable de entorno de Windows .


Actualizar:

Parece que Oracle ha eliminado el PDF de su sitio web. Actualicé el enlace anterior para señalar una instancia del PDF que vive en la Universidad de Texas - Arlington.

Además, también puede leer la versión HTML de Oracle de la especificación JNI . Eso vive en la sección Java 8 del sitio web de Java y, por lo tanto, con suerte estará disponible por un tiempo.


Actualización 2:

Al menos en Java 8 (no he comprobado versiones anteriores) puede hacer:

java -XshowSettings:properties -version

para encontrar la ruta de búsqueda de la biblioteca compartida. Busque el valor de la java.library.pathpropiedad en esa salida.

Mecánica cuántica
fuente
2
Sí, CLASSPATHno se usa en absoluto. Tampoco estoy seguro de que cwdse use en absoluto. java.library.patho simplemente PATHfuncionará. @dB ', el lugar donde los tiene ahora es incorrecto .
Ernest Friedman-Hill
¡Muchas gracias chicos! Creo que parte del problema aquí fue una confusión de mi parte entre la variable de entorno Windows PATH, java.library.path y java CLASSPATH. Todo tiene más sentido ahora.
dB '23 de
Por favor, ¿puede explicar cómo superó este problema?
SL_User
5
@SL_User Creo que si agrega el directorio donde están las bibliotecas a la variable de entorno "ruta" y reinicia el símbolo del sistema o el terminal, debería solucionarlo. Java busca archivos jar en classpath y bibliotecas en path.
xxjjnn
1
Según esta respuesta, parece que el comando para la Actualización 2 ha estado disponible desde al menos Java 7: stackoverflow.com/a/8472139/901641
ArtOfWarfare
18

Quiero informar este interesante caso, después de probar todo el método anterior, el error sigue ahí. Lo extraño es que funciona en una computadora con Windows 7, pero en Windows XP no. Luego utilizo el andador de dependencia y descubrí que en Windows XP no hay VC ++ Runtime como requisito de mi dll. Después de instalar el paquete VC ++ Runtime aquí , funciona como un encanto. Lo que me molestó es que sigue diciendo No se pueden encontrar bibliotecas dependientes, mientras que intuitivamente la dll dependiente de JNI está ahí, sin embargo, finalmente resulta que la dll dependiente de JNI requiere otra dl dependiente. Espero que esto ayude.

longbkit
fuente
4
El mensaje es correcto, aunque engañoso en este caso. Faltaban los tiempos de ejecución de VC ++ en el cuadro de prueba y la biblioteca compilada en el modo de depuración (dependiendo de los tiempos de ejecución de depuración no distribuibles). Dependency Walker fue de gran ayuda para resolver esto.
Johnny Baloney
tenía el mismo problema al usar jnetpcap-library. la dependencia winpcap ya no estaba instalada en la máquina y el mensaje de excepción era engañoso
BlackFlag
Estoy pensando que este podría ser mi caso.
I.Tyger
En estos días, el caminante de la dependencia se está volviendo bastante "largo en el diente". No pudo abrir una dll reciente de Windows 10/64-bit en absoluto, así que todavía no tengo idea de qué biblioteca falta ... Whee.
Mark Storer
5

Verifique que la ruta de su biblioteca sea correcta o no. Por supuesto, puede usar el siguiente código para verificar la ruta de su biblioteca: System.out.println(System.getProperty("java.library.path"));

Puede designar java.library.path al iniciar una aplicación Java:

java -Djava.library.path=path ...
caopeng
fuente
4

Si carga una versión de 32 bits de su dll con un JRE de 64 bits, podría tener este problema. Este fue mi caso.

EFalco
fuente
Es muy probable que este también sea mi caso; si alguien conoce soluciones alternativas conocidas, me interesaría; excepto cargar una versión de 64 bits, ya que en este caso el proceso no es un dll sino chromedriver.exeel controlador Selenium para Chrome, que por lo que puedo decir solo viene en la versión de 32 bits.
SantiBailors
4

Tuve un problema idéntico con la máquina XP al instalar javacvy opencven combinación con Eclipse. Resultó que me faltaban los siguientes archivos:

  • msvcp100.dll
  • msvcr100.dll

Una vez instalados, el proyecto se compiló y se ejecutó correctamente.

Rob van Riswick
fuente
Tengo un problema similar que desaparece después de instalar "Microsoft Visual C ++ 2010 SP1 Redistributable Package (x86)"
Kirill Mikhailov
2
  • Respuesta corta: para el error "no se puede encontrar la biblioteca dependiente", verifique su $ PATH (corresponde al punto 3 a continuación)
  • Respuesta larga:
    1. Pure java world: jvm usa "Classpath" para encontrar archivos de clase
    2. JNI world (java / native boundary): jvm usa "java.library.path" (que por defecto es $ PATH) para encontrar dlls
    3. mundo nativo puro: el código nativo usa $ PATH para cargar otros dlls
usuario2038596
fuente
2

Encontré un gran artículo de algunos amigos en keepsafe que pasó por lo mismo que yo. Me funcionó, ¡así que espero que también te ayude! Lea si está interesado ( Los peligros de cargar bibliotecas nativas en Android ) o simplemente use

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

y reemplazar

System.loadLibrary("myLibrary");

con

ReLinker.loadLibrary(context, "mylibrary");
rhysl
fuente
1

Solía ​​tener exactamente el mismo problema y finalmente se resolvió.

Pongo todas las DLL dependientes en la misma carpeta donde se almacenó mylib.dll y me aseguro de que el compilador JAVA pueda encontrarlo (si no hay mylib.dll en la ruta de compilación, habría un error al informar esto durante la compilación). Lo importante que debe tener en cuenta es que debe asegurarse de que todas las bibliotecas dependientes sean de la misma versión que mylib.dll, por ejemplo, si mylib.dll es la versión de lanzamiento, también debe colocar la versión de lanzamiento de todas sus bibliotecas dependientes allí. .

Espero que esto pueda ayudar a otros que se han encontrado con el mismo problema.

Steven Peng
fuente
1

Tuve el mismo problema e intenté todo lo que se publica aquí para solucionarlo, pero ninguno funcionó para mí. En mi caso, estoy usando Cygwin para compilar el dll. Parece que JVM intenta encontrar las DLL de JRE en la ruta virtual de Cygwin. Agregué la ruta del directorio virtual de Cygwin a las DLL de JRE y ahora funciona. Hice algo como:

SET PATH = "/ cygdrive / c / Archivos de programa / Java / jdk1.8.0_45";% PATH%

estebanuri
fuente
1

En mi situación, estaba intentando ejecutar un servicio web java en Tomcat 7 a través de un conector en Eclipse. La aplicación funcionó bien cuando implementé el archivo war en una instancia de Tomcat 7 en mi computadora portátil. La aplicación requiere un controlador jdbc tipo 2 para "IBM DB2 9.5". Por alguna extraña razón, el conector en Eclispe no pudo ver o usar las rutas en las variables de entorno de IBM DB2 para llegar a los archivos dll instalados en mi computadora portátil como el cliente jcc. El mensaje de error indicaba que no pudo encontrar el archivo dll db2jcct2 o no pudo encontrar las bibliotecas dependientes para ese archivo dll. Al final, eliminé el conector y lo reconstruí. Entonces funcionó correctamente. Estoy agregando esta solución aquí como documentación, porque no pude encontrar esta solución específica en ningún otro lugar.

bwfrieds
fuente
0

La creación de una biblioteca estática funcionó para mí, compilando usando g++ -static. Incluye las bibliotecas dependientes junto con build.

César
fuente
0

instalación de Microsoft Visual C ++ 2010 SP1 Redistributable Fix it

Sunil Kumar
fuente
0

coloque los archivos DLL necesarios en la carpeta y establezca la ruta de la carpeta en la variable de entorno PATH. asegúrese de que se refleje la variable PATH del entorno actualizada.

user3122472
fuente
0

Enfrentaba el mismo problema con la biblioteca ffmpeg después de fusionar dos proyectos de Android como un solo proyecto.

En realidad, el problema estaba llegando debido a dos versiones diferentes de la biblioteca ffmpeg, pero estaban cargadas con los mismos nombres en la memoria. Una biblioteca se colocó en JNiLibs mientras que otra estaba dentro de otra biblioteca utilizada como módulo. No pude modificar el código del módulo ya que era de solo lectura, así que cambié el nombre del que usé en mi propio código a ffmpegCamera y lo cargué en la memoria con el mismo nombre.

System.loadLibrary("ffmpegCamera");

Esto resolvió el problema y ahora ambas versiones de las bibliotecas se cargan bien con un nombre y un ID de proceso separados en la memoria.

Mohsin Raza
fuente
0

Al llamar System.loadLibrary(), la JVM buscará en eljava.library.path su biblioteca nativa. Sin embargo, si esa biblioteca nativa declara alguna dependencia en otras bibliotecas nativas, entonces el sistema operativo tendrá la tarea de encontrar esas dependencias de biblioteca nativa.

Dado que el sistema operativo no tiene el concepto de java.library.path, no verá ningún directorio que coloque en java.library.path. En su lugar, solo buscará los directorios en la variable de entorno PATH del sistema operativo. Esto está totalmente bien si la dependencia de la biblioteca nativa es una biblioteca nativa del sistema operativo porque se encontrará en la RUTA. Sin embargo, si la dependencia de la biblioteca nativa es una biblioteca nativa que usted u otra persona creó, no se encontrará en la RUTA a menos que la coloque allí. Este comportamiento es extraño, inesperado y no está bien documentado, pero está documentado en el rastreador de problemas de OpenJDK aquí . También puede encontrar otra respuesta de StackOverflow que refuerce esta explicación, aquí .

Entonces, tienes un par de opciones. Puede cargar cada biblioteca nativa en el orden de dependencia correcto usando System.loadLibrary(), o puede modificar la RUTA para incluir los directorios donde se almacenan sus bibliotecas nativas.

Región39
fuente
-2
  1. Vaya a http://tess4j.sourceforge.net/usage.html y haga clic enVisual C++ Redistributable for VS2012
  2. Descárguelo y ejecútelo VSU_4\vcredist_x64.exeo VSU_4\vcredist_x84.exedependiendo de la configuración de su sistema
  3. Coloque sus dllarchivos dentro de la libcarpeta, junto con sus otras bibliotecas (por ejemplo \lib\win32-x86\your dll files).
Pratik Varpe
fuente