2011-03-24 16 views
5

Estoy envolviendo una biblioteca compartida (escrita en C) con Java usando JNA. La biblioteca compartida está escrita internamente, pero esa biblioteca utiliza funciones de otra biblioteca externa, que de nuevo depende de otra biblioteca externa. Así que la situación es algo como esto:Java: cargar bibliotecas compartidas con dependencias

ext1 < - ext2 < - interno

es decir, el interno usa la biblioteca externa ext2 que nuevamente usa la biblioteca externa ext1. Lo que he intentado es:

System.loadLibrary("ext1"); 
System.loadLibrary("ext2"); 
NativeLIbrary.loadLibrary("internal",xxx.class); 

Este enfoque falla con "UnresolvedException" al cargar la biblioteca "ext2"; el enlazador se queja de símbolos que de hecho están presentes en la biblioteca "ext1". Entonces, ¿cree que la función System.loadLibrary() no hace que los símbolos de "ext1" estén disponibles globalmente? Cuando se utiliza el dlopen función stdlib() como:

handle = dlopen(lib_name , RTLD_GLOBAL); 

Todos los símbolos que se encuentra en @lib_name estará disponible para la resolución de símbolo en cargas posteriores; Supongo que lo que me gustaría es algo similar para la variedad java System.loadLibrary()?

Saludos - Joakim Hove

+0

es el camino a las bibliotecas definidas en la propiedad 'java.library.path' Java? –

+0

Bueno, ubicar las bibliotecas es en realidad otra queja, y he recurrido al uso de System.load (full_path_to_shared_library), pero ese problema creo que es principalmente un problema de netbeans. La excepción al cargar la biblioteca "ext" es durante la fase de resolución del símbolo, es decir, la biblioteca se ha ubicado correctamente, y así sucesivamente. Creo/temo que esto está relacionado con el indicador RTLD_GLOBAL (o la falta de él) en la llamada de bajo nivel dlopen() en el fondo en el tiempo de ejecución. – user422005

Respuesta

2

Aceptar;

He encontrado una solución aceptable al final, pero no sin una cantidad significativa de aros. Lo que hago es

  1. Utilice el mecanismo JNA normal para asignar la función dlopen() de la biblioteca de enlaces dinámicos (libdl.so).
  2. Utilice la función dlopen() asignada con JNA para cargar las bibliotecas externas "ext1" y "ext2" con la opción RTLD_GLOBAL establecida.

En realidad, parece que funciona :-)

0

Prueba de esto, añadir esta función a su código. Llámalo antes de cargar tus dlls. Para el parámetro, usa la ubicación de tus dlls.

 

    public boolean addDllLocationToPath(String dllLocation) 
    { 
     try 
     { 
      System.setProperty("java.library.path", System.getProperty("java.library.path") + ";" + dllLocation); 
      Field fieldSysPath = ClassLoader.class.getDeclaredField("sys_paths"); 
      fieldSysPath.setAccessible(true); 
      fieldSysPath.set(null, null); 
     } 
     catch (Exception e) 
     { 
      System.err.println("Could not modify path"); 
      return false; 
     } 
     return true; 
    } 
} 
 
+1

Gracias por el esfuerzo: su sugerencia funciona bien cuando se trata de ubicar las bibliotecas. Pero desafortunadamente ese no es mi problema, el problema es que los símbolos en la biblioteca "ext2" no están disponibles para las funciones en "ext1" - cuando se usa directamente la llamada a la biblioteca dlopen() (tal vez eso es lo que debo hacer ???) este comportamiento está controlado por un indicador entero, y el comportamiento que busco se logra con el indicador RTLD_GLOBAL. ¡Esto parecía ser más difícil de lo que pensaba! – user422005

2

Es una vieja pregunta, pero he encontrado una solución aceptable, que también debe ser portátil, y pensé que debería publicar una respuesta. La solución es usar JNA 's NativeLibrary#getInstance(), porque en Linux esto pasará RTLD_GLOBAL a dlopen() (y en Windows esto no es necesario).

Ahora, si usted está usando esta biblioteca para implementar un native método Java, que también tendrá que llamar System.load() (o Sysem.loadLibrary()) en la misma biblioteca, después de llamar NativeLibrary#getInstance().

En primer lugar, un enlace a un error JNA: JNA-61

Un comentario de allí dice que, básicamente, se debe cargar antes de las dependencias de la biblioteca real de usar desde dentro JNA, no es la forma estándar de Java. Voy a copiar y pegar el código, que es un escenario típico:

String libPath = 
     "/path/to/my/lib:" + // My library file 
     "/usr/local/lib:" + // Libraries lept and tesseract 
     System.getProperty("java.library.path"); 

System.setProperty("jna.library.path", libPath); 

NativeLibrary.getInstance("lept"); 
NativeLibrary.getInstance("tesseract"); 
OcrTesseractInterf ocrInstance = (OcrTesseractInterf) 
     Native.loadLibrary(OcrTesseractInterf.JNA_LIBRARY_NAME, OcrTesseractInterf.class); 

He escrito una pequeña biblioteca para proporcionar capacidad de OCR para mi aplicación Java utilizando Tesseract.Tesseract depende de Leptonica, entonces para usar mi biblioteca, primero necesito cargar las bibliotecas lept y tesseract. Cargar las bibliotecas con los medios estándar (System.load() y System.loadLibrary()) no funciona, tampoco las propiedades de configuración jna.library.path o java.library.path. Obviamente, a JNA le gusta cargar bibliotecas a su manera.

Esto funciona para mí en Linux, supongo que si uno establece la ruta adecuada de la biblioteca, esto debería funcionar en otros sistemas operativos también.

1

Hay otra solución para eso. Puede dlopen directamente en el interior de código JNI, así:

void loadLibrary() { 
    if(handle == NULL) { 
    handle = dlopen("libname.so", RTLD_LAZY | RTLD_GLOBAL); 
    if (!handle) { 
     fprintf(stderr, "%s\n", dlerror()); 
     exit(EXIT_FAILURE); 
    } 
    } 
} 

... 
... 

loadLibrary(); 

De esta forma, se abrirá la biblioteca con RTLD_GLOBAL.

Puede encontrar la descripción detallada aquí: http://www.owsiak.org/?p=3640

+0

Gracias, he estado en este problema durante horas y ninguna de las soluciones anteriores funcionó – dargaud

+0

.oOo. Gracias;) .oOo. – mko

Cuestiones relacionadas