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

92

¿Cómo puedo cargar un archivo dll personalizado en mi aplicación web? He intentado lo siguiente:

  • Copió todos los archivos DLL requeridos en la system32carpeta e intentó cargar uno de ellos en el ServletconstructorSystem.loadLibrary
  • Copiado los dlls necesarios en tomcat_home/shared/libytomcat_home/common/lib

Todos estos dlls están en WEB-INF/libla aplicación web

Ketan Khairnar
fuente

Respuestas:

156

Para System.loadLibrary()que funcione, la biblioteca (en Windows, una DLL) debe estar en un directorio en algún lugar de usted PATH o en una ruta listada en la java.library.pathpropiedad del sistema (para que pueda iniciar Java como java -Djava.library.path=/path/to/dir).

Además, para loadLibrary(), especifica el nombre base de la biblioteca, sin el .dllal final. Entonces, /path/to/something.dllsolo usarías System.loadLibrary("something").

También necesita mirar exactamente lo UnsatisfiedLinkErrorque está obteniendo. Si dice algo como:

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

entonces no puede encontrar la biblioteca foo (foo.dll) en su PATHo java.library.path. Si dice algo como:

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

entonces algo anda mal con la propia biblioteca en el sentido de que Java no puede mapear una función nativa de Java en su aplicación a su contraparte nativa real.

Para empezar, pondría algunos registros alrededor de su System.loadLibrary()llamada para ver si se ejecuta correctamente. Si arroja una excepción o no está en una ruta de código que realmente se ejecuta, siempre obtendrá el último tipo de UnsatisfiedLinkErrorexplicado anteriormente.

Como nota al margen, la mayoría de las personas colocan sus loadLibrary()llamadas en un bloque inicializador estático en la clase con los métodos nativos, para asegurarse de que siempre se ejecute exactamente una vez:

class Foo {

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

    public Foo() {
    }

}
Adam Batkin
fuente
1
Al poner todos los archivos DLL en System32 y usar System.loadLibrary ("algo") funcionó. Estaba haciendo System.loadLibrary ("something.dll") antes. ¿Por qué no puede cargar todas las DLL de WEB-INF? Supongo que carga todos los frascos de forma predeterminada. ¿Qué puedo hacer para cargar estos dlls desde WEB-INF directamente en lugar de System32 / especificarlos en java.library.path
Ketan Khairnar
2
+1 para el "uso" bla "en lugar de" bla.dll "para el loadLibrary()comentario - muy útil cuando no tiene idea de lo que está haciendo mal.
MarnixKlooster ReinstateMonica
21
En mi sistema (Linux y java7), necesito un libprefijo. Así que System.loadLibrary("foo")necesita libfoo.so.
kristianlm
2
Gracias. Me funcionó cuando actualicé "PATH" para Windows para que contenga una carpeta con un archivo * .so.
user613114
Podría haber jurado que se requería OSX blah.jniliby Linux libblah.so. Bueno, dos horas después, después de numerosos intentos, llegué a la conclusión de que OSX también requiere libprefijo
Jovan Perovic
15

Cambiar la variable 'java.library.path' en tiempo de ejecución no es suficiente porque JVM solo la lee una vez. Tienes que restablecerlo como:

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);

Por favor, obtenga un botín en: Changing Java Library Path at Runtime .

Alexandre
fuente
10

La respuesta original de Adam Batkin lo llevará a una solución, pero si vuelve a implementar su aplicación web (sin reiniciar su contenedor web), debería encontrarse con el siguiente error:

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)

Esto sucede porque el ClassLoader que originalmente cargó su DLL todavía hace referencia a este DLL. Sin embargo, su aplicación web ahora se está ejecutando con un nuevo ClassLoader, y debido a que se está ejecutando la misma JVM y una JVM no permitirá 2 referencias a la misma DLL, no puede volver a cargarla . Por lo tanto, su aplicación web no puede acceder a la DLL existente y no puede cargar una nueva. Entonces ... estás atascado.

La documentación de ClassLoader de Tomcat describe por qué su aplicación web recargada se ejecuta en un nuevo ClassLoader aislado y cómo puede evitar esta limitación (a un nivel muy alto).

La solución es extender un poco la solución de 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) {
        }

    }

Luego coloque un jar que contenga SOLO esta clase compilada en la carpeta TOMCAT_HOME / lib.

Ahora, dentro de su aplicación web, solo tiene que obligar a Tomcat a hacer referencia a esta clase, lo que se puede hacer de manera tan simple como esto:

  Class.forName("awesome.Foo");

Ahora su DLL debe cargarse en el cargador de clases común y puede ser referenciado desde su aplicación web incluso después de volver a implementarlo.

¿Tener sentido?

Se puede encontrar una copia de referencia funcional en el código de Google, static-dll-bootstrapper .

Matt M
fuente
1
Esta respuesta es excelente para los servidores de aplicaciones y debería tener su propia pregunta, ya que se desperdicia en esta pregunta.
JoshDM
8

Puede utilizar System.load()para proporcionar una ruta absoluta que es lo que desea, en lugar de un archivo en la carpeta de la biblioteca estándar para el sistema operativo respectivo.

Si desea aplicaciones nativas que ya existen, use System.loadLibrary(String filename). Si desea proporcionar el suyo, probablemente sea mejor con load ().

También debería poder utilizarlo correctamente loadLibrarycon el java.library.pathconjunto. Consulte la ClassLoader.javafuente de implementación que muestra ambas rutas que se están verificando (OpenJDK)

Philip Whitehouse
fuente
Gracias. Usar la carga es en realidad mucho más fácil e intuitivo en mi humilde opinión. No se pudo hacer que loadLibrary funcionara sin importar lo que hice ...
Plankalkül
2
Esta solución no funciona para bibliotecas que cargan sus propias bibliotecas nativas.
Justin Skiles
7

En el caso de que el problema sea que System.loadLibrary no puede encontrar la DLL en cuestión, un error común (reforzado por el mensaje de error de Java) es que la propiedad del sistema java.library.path es la respuesta. Si establece la propiedad del sistema java.library.path en el directorio donde se encuentra su DLL, System.loadLibrary encontrará su DLL. Sin embargo, si su DLL a su vez depende de otras DLL, como suele ser el caso, entonces java.library.path no puede ayudar, porque la carga de las DLL dependientes es administrada completamente por el sistema operativo, que no sabe nada de java.library. camino. Por lo tanto, casi siempre es mejor omitir java.library.path y simplemente agregar el directorio de su DLL a LD_LIBRARY_PATH (Linux), DYLD_LIBRARY_PATH (MacOS) o Path (Windows) antes de iniciar la JVM.

(Nota: estoy usando el término "DLL" en el sentido genérico de DLL o biblioteca compartida).

Ian Emmons
fuente
5

Si necesita cargar un archivo que es relativo a algún directorio donde ya se encuentra (como en el directorio actual), aquí tiene una solución fácil:

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());
Rick C. Hodgin
fuente
4

Para los que buscan java.lang.UnsatisfiedLinkError: no pdf_java in java.library.path

Me enfrentaba a la misma excepción; Probé todo y las cosas importantes para que funcione son:

  1. Versión correcta de pdf lib.jar (en mi caso, la versión jar incorrecta se mantuvo en el tiempo de ejecución del servidor)
  2. Haga una carpeta y mantenga el archivo pdflib jar en ella y agregue la carpeta en su variable PATH

Funcionó con tomcat 6.

Mangesh M. Kulkarni
fuente
3
  1. Si cree que agregó una ruta de biblioteca nativa a %PATH%, intente probar con:

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

Debería mostrarte si tu dll está activado %PATH%

  1. Reinicie IDE Idea, que pareció funcionar para mí después de configurar la variable env agregándola a la %PATH%
AlexPes
fuente
2

Pobre de mí ! Pasé un día entero detrás de esto. Escribiéndolo aquí si algún organismo replica este problema.

Estaba tratando de cargar como sugirió Adam, pero luego me atraparon con la excepción AMD64 vs IA 32.Si en cualquier caso, después de trabajar según el tutorial de Adam (sin duda la mejor opción), intente tener una versión de 64 bits del último jre. su JRE Y JDK son de 64 bits y lo ha agregado correctamente a su classpath.

Mi ejemplo de trabajo va aquí: error de enlace no declarado

sayannayas
fuente
0

Para Windows, descubrí que cuando cargué los archivos (llamadas jd2xsx.dll y ftd2xx.dll) en la carpeta windowws / system32, esto resolvió los problemas. Luego tuve un problema con mi nuevo fd2xx.dll que tenía que ver con los parámetros, por lo que tuve que cargar la versión anterior de este dll. Tendré que sacar esto más tarde.

Nota: jd2xsx.dll llama a ftd2xx.dll, por lo que es posible que la configuración de la ruta para jd2xx.dll no funcione.

Dan Carte
fuente
0

Estoy usando Mac OS X Yosemite y Netbeans 8.02, obtuve el mismo error y la solución simple que encontré es como la anterior, esto es útil cuando necesita incluir una biblioteca nativa en el proyecto. Entonces haz lo siguiente para 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

Espero que pueda ser de utilidad para alguien. El enlace donde encontré la solución está aquí: java.library.path - ¿Qué es y cómo usarlo?

alexventuraio
fuente
Hola Alex, tengo una pregunta aquí, ¿hay algún problema si la ruta de la biblioteca incluye algún espacio en la ruta en esta línea?VM Options: java -Djava.library.path="your_path"
Lokesh Pandey
Mmm, no estoy trabajando con Java durante el último año, pero como pueden aparecer conflictos, recomiendo evitar agregar espacios vacíos en la ruta del archivo .
alexventuraio
0

Tuve el mismo problema y el error se debió a un cambio de nombre de la dll. Podría suceder que el nombre de la biblioteca también esté escrito en algún lugar dentro de la dll. Cuando devolví su nombre original, pude cargar usandoSystem.loadLibrary

Alessandro Marini
fuente
0

Es simple, simplemente escriba java -XshowSettings: properties en su línea de comando en Windows y luego pegue todos los archivos en la ruta mostrada por java.library.path.

Ali Sasoli
fuente