¿Cómo agrupar una biblioteca nativa y una biblioteca JNI dentro de un JAR?

Resuelto Alex B asked hace 14 años • 7 respuestas

La biblioteca en cuestión es el Gabinete de Tokio .

Lo que quiero es tener la biblioteca nativa, la biblioteca JNI y todas las clases de API de Java en un archivo JAR para evitar dolores de cabeza por la redistribución.

Parece haber un intento de esto en GitHub , pero

  1. No incluye la biblioteca nativa real, solo la biblioteca JNI.
  2. Parece ser específico del complemento de dependencias nativas de Leiningen (no funcionará como redistribuible).

La pregunta es, ¿puedo agrupar todo en un JAR y redistribuirlo? Si es así, ¿cómo?

PD: Sí, me doy cuenta de que puede tener implicaciones de portabilidad.

Alex B avatar May 30 '10 10:05 Alex B
Aceptado

Es posible crear un único archivo JAR con todas las dependencias, incluidas las bibliotecas JNI nativas para una o más plataformas. El mecanismo básico es utilizar System.load(File) para cargar la biblioteca en lugar del típico System.loadLibrary(String) que busca la propiedad del sistema java.library.path. Este método simplifica mucho la instalación, ya que el usuario no tiene que instalar la biblioteca JNI en su sistema, pero a costa de que no todas las plataformas sean compatibles, ya que la biblioteca específica de una plataforma podría no estar incluida en un único archivo JAR. .

El proceso es el siguiente:

  • incluya las bibliotecas JNI nativas en el archivo JAR en una ubicación específica de la plataforma, por ejemplo en NATIVE/${os.arch}/${os.name}/libname.lib
  • crear código en un inicializador estático de la clase principal para
    • Calc el actual os.arch y os.name
    • busque la biblioteca en el archivo JAR en la ubicación predefinida usando Class.getResource(String)
    • si existe, extráigalo a un archivo temporal y cárguelo con System.load(File).

Agregué funcionalidad para hacer esto para jzmq, los enlaces Java de ZeroMQ (complemento descarado). El código se puede encontrar aquí . El código jzmq utiliza una solución híbrida de modo que si no se puede cargar una biblioteca integrada, el código volverá a buscar la biblioteca JNI a lo largo de java.library.path.

kwo avatar Jun 28 '2011 18:06 kwo

https://www.adamheinrich.com/blog/2012/12/how-to-load-native-jni-library-from-jar/

Es un gran artículo, que resuelve mi problema.

En mi caso tengo el siguiente código para inicializar la biblioteca:

static {
    try {
        System.loadLibrary("crypt"); // used for tests. This library in classpath only
    } catch (UnsatisfiedLinkError e) {
        try {
            NativeUtils.loadLibraryFromJar("/natives/crypt.dll"); // during runtime. .DLL within .JAR
        } catch (IOException e1) {
            throw new RuntimeException(e1);
        }
    }
}
davs avatar Dec 27 '2012 08:12 davs

JarClassLoader es un cargador de clases para cargar clases, bibliotecas nativas y recursos desde un único JAR monstruoso y desde archivos JAR dentro del JAR monstruoso.

tekumara avatar Dec 03 '2010 04:12 tekumara

Solución para Kotlin:

  • build.gradle.dsl: copie el tiempo de ejecución de Kotlin (kotlin-stdlib-1.4.0.jar) y la biblioteca nativa (librust_kotlin.dylib) en JAR

    tasks.withType<Jar> {
        manifest {
            attributes("Main-Class" to "MainKt")
        }
    
        val libs = setOf("kotlin-stdlib-1.4.0.jar")
    
        from(configurations.runtimeClasspath.get()
            .filter { it.name in libs }
            .map { zipTree(it) })
    
        from("librust_kotlin.dylib")
    }
    
  • mainmétodo: copie la biblioteca a un archivo temporal para cargarla usando la ruta absoluta

     with(createTempFile()) {
         deleteOnExit()
         val bytes = My::class.java.getResource("librust_kotlin.dylib")
             .readBytes()
    
         outputStream().write(bytes)
         System.load(path)
     }
    
Max Farsikov avatar Sep 01 '2020 19:09 Max Farsikov