Error de enlace insatisfecho - cargas de biblioteca, no se encontró la entrada

Gus:

Estoy tratando de vincular un (bastante grande) biblioteca nativa escrita por un cliente en código Java. He escrito esta clase ensayo simplificado que intenta cargar la biblioteca y trivialmente llamar a un método nativo de la biblioteca. También he añadido algo de código de depuración.

public class JniVtaTest {

  static {
    try {
      Process exec = Runtime.getRuntime().exec("ldd /usr/java/packages/lib/libvtajni.so");
      byte[] bytes = exec.getErrorStream().readAllBytes();
      System.out.println(new String(bytes));
      bytes = exec.getInputStream().readAllBytes();
      System.out.println(new String(bytes));
    } catch (IOException e) {
      e.printStackTrace();
    }
    String property = System.getProperty("java.library.path");
    System.out.println(property);

    // above code generates the debugging outpout shown below
    System.loadLibrary("vtajni");
  }

  // running with options:
  // -Djava.library.path="/usr/java/packages/lib:/usr/lib64:/lib64:/lib:/usr/lib:/usr/lib/x86_64-linux-gnu:/lib/x86_64-linux-gnu" -verbose:jni -Xcheck:jni

  public static void main(String[] args) {
    new JniVtaTest().vtaAnalyze(args[0]);
  }

  private native String vtaAnalyze(String str);
}

Cuando corro lo anterior con las opciones indicadas, tengo una gran cantidad de la producción JVM sobre la vinculación dinámica de clases JVM y entonces esto:

    linux-vdso.so.1 (0x00007ffe2239d000)
    libiodbc.so.2 => /usr/lib/x86_64-linux-gnu/libiodbc.so.2 (0x00007ff6093b1000)
    libstdc++.so.6 => /usr/lib/x86_64-linux-gnu/libstdc++.so.6 (0x00007ff609028000)
    libm.so.6 => /lib/x86_64-linux-gnu/libm.so.6 (0x00007ff608c8a000)
    libgcc_s.so.1 => /lib/x86_64-linux-gnu/libgcc_s.so.1 (0x00007ff608a72000)
    libc.so.6 => /lib/x86_64-linux-gnu/libc.so.6 (0x00007ff608681000)
    libdl.so.2 => /lib/x86_64-linux-gnu/libdl.so.2 (0x00007ff60847d000)
    /lib64/ld-linux-x86-64.so.2 (0x00007ff62713d000)

11.0.5
/usr/java/packages/lib:/usr/lib64:/lib64:/lib:/usr/lib:/usr/lib/x86_64-linux-gnu:/lib/x86_64-linux-gnu
Exception in thread "main" java.lang.UnsatisfiedLinkError: 'java.lang.String com.customer.jni.JniVtaTest.vtaAnalyze(java.lang.String)'
    at com.customer.jni.JniVtaTest.vtaAnalyze(Native Method)
    at com.customer.jni.JniVtaTest.main(JniVtaTest.java:26)

Todas las bibliotecas que se cargan por la biblioteca parecen existir:

gus@ns-l1:/usr/java/packages$ ls -al /usr/lib/x86_64-linux-gnu/libiodbc.so.2
lrwxrwxrwx 1 root root 18 Dec 12  2017 /usr/lib/x86_64-linux-gnu/libiodbc.so.2 -> libiodbc.so.2.1.20
gus@ns-l1:/usr/java/packages$ ls -al /usr/lib/x86_64-linux-gnu/libstdc++.so.6
lrwxrwxrwx 1 root root 19 Dec  4 09:45 /usr/lib/x86_64-linux-gnu/libstdc++.so.6 -> libstdc++.so.6.0.25
gus@ns-l1:/usr/java/packages$ ls -al /lib/x86_64-linux-gnu/libm.so.6
lrwxrwxrwx 1 root root 12 Apr 16  2018 /lib/x86_64-linux-gnu/libm.so.6 -> libm-2.27.so
gus@ns-l1:/usr/java/packages$ ls -al /lib/x86_64-linux-gnu/libgcc_s.so.1
-rw-r--r-- 1 root root 96616 Dec  4 09:45 /lib/x86_64-linux-gnu/libgcc_s.so.1
gus@ns-l1:/usr/java/packages$ ls -al /lib/x86_64-linux-gnu/libc.so.6
lrwxrwxrwx 1 root root 12 Apr 16  2018 /lib/x86_64-linux-gnu/libc.so.6 -> libc-2.27.so
gus@ns-l1:/usr/java/packages$ ls -al /lib/x86_64-linux-gnu/libdl.so.2
lrwxrwxrwx 1 root root 13 Apr 16  2018 /lib/x86_64-linux-gnu/libdl.so.2 -> libdl-2.27.so
gus@ns-l1:/usr/java/packages$ ls -al /lib64/ld-linux-x86-64.so.2
lrwxrwxrwx 1 root root 32 Apr 16  2018 /lib64/ld-linux-x86-64.so.2 -> /lib/x86_64-linux-gnu/ld-2.27.so
gus@ns-l1:/usr/java/packages$ 

También son fáciles de encontrar a través de todo ldconfig -v -Ny yo nos registramos que ldconfig no encuentra ninguna biblioteca con los leters vtaen ella como este, así que creo que estoy a salvo de nombre de la superposición accidental:

ldconfig -v -N 2>&1 | grep vta
(no output shown)

La biblioteca del cliente en sí está cargado con claridad porque cuando elimino errores no muere en la biblioteca de carga, el depurador se detendrá en la línea de invocar el método y, bajando en este código JVM indica que ha encontrado una biblioteca llamada /usr/java/packages/lib/libvtajni.soy que entra en el para el primer bucle de buscar Java_com_customer_jni_JniVtaTest_vtaAnalyzey luego otra vez en busca de Java_com_customer_jni_JniVtaTest_vtaAnalyze__Ljava_lang_String_2(parece que revise dos veces para cada una de ellas)

    private static long findNative(ClassLoader loader, String entryName) {
        Map<String, NativeLibrary> libs =
            loader != null ? loader.nativeLibraries() : systemNativeLibraries();
        if (libs.isEmpty())
            return 0;

        // the native libraries map may be updated in another thread
        // when a native library is being loaded.  No symbol will be
        // searched from it yet.
        for (NativeLibrary lib : libs.values()) {
            long entry = lib.findEntry(entryName); <<<<< STOP DEBUGGER HERE
            if (entry != 0) return entry;
        }
        return 0;
    }

El archivo de cabecera generado con javah com.customer.jni.JniVtaTest el siguiente aspecto:

/* DO NOT EDIT THIS FILE - it is machine generated */
#include <jni.h>
/* Header for class com_customer_jni_JniVtaTest */

#ifndef _Included_com_customer_jni_JniVtaTest
#define _Included_com_customer_jni_JniVtaTest
#ifdef __cplusplus
extern "C" {
#endif
/*
 * Class:     com_customer_jni_JniVtaTest
 * Method:    vtaAnalyze
 * Signature: (Ljava/lang/String;)Ljava/lang/String;
 */
JNIEXPORT jstring JNICALL Java_com_customer_jni_JniVtaTest_vtaAnalyze
  (JNIEnv *, jobject, jstring);

#ifdef __cplusplus
}
#endif
#endif

El método en el archivo CPP se ve así:

JNIEXPORT jstring JNICALL Java_com_customer_jni_JniVtaTest_vtaAnalyze
        (JNIEnv * env, jobject obj, jstring jInputText) {
    cout << "foo";

    // customer code...

    return  env->NewStringUTF(obuf);
}

Y nunca veo fooimpreso, así que no creo que es encontrar el método y luego no dentro del método.

JDK completo y sistema (Ubuntu 18.04) Info:

openjdk 11.0.5 2019-10-15 LTS
OpenJDK Runtime Environment Zulu11.35+15-CA (build 11.0.5+10-LTS)
OpenJDK 64-Bit Server VM Zulu11.35+15-CA (build 11.0.5+10-LTS, mixed mode)

Linux ns-l1 4.15.0-88-generic #88-Ubuntu SMP Tue Feb 11 20:11:34 UTC 2020 x86_64 x86_64 x86_64 GNU/Linux

Horas de búsqueda y la lectura de las páginas como https://developer.android.com/training/articles/perf-jni#faq:-why-do-i-get-unsatisfiedlinkerror- y la especificación en https://docs.oracle .com / es / java / JavaSE / 11 / docs / especificaciones / JNI / design.html # resolver nativo-método de nombres me han dejado rascándome la cabeza.

Mi pregunta: ¿Por qué estoy recibiendo este error? ¿Qué he echado de menos.

Editar : por la pregunta en los comentarios no encuentro el símbolo con el nm -Dpero yo encuentro algo con nm -A... Ahora tengo que averiguar por qué es así.

gus@ns-l1:~/clients/customer/code/vta_jni$ nm -A /usr/java/packages/lib/libvtajni.so | grep com_
/usr/java/packages/lib/libvtajni.so:00000000112a3d38 t _GLOBAL__sub_I__Z44Java_com_customer_jni_JniVtaTest_vtaAnalyzeP7JNIEnv_P8_jobjectP8_jstring
/usr/java/packages/lib/libvtajni.so:00000000112a388a T _Z44Java_com_customer_jni_JniVtaTest_vtaAnalyzeP7JNIEnv_P8_jobjectP8_jstring

Editar 2 : El archivo de cabecera se incluye a través ...

#include "com_customer_jni_JniVtaTest.h"

Datos 3 : Después de cambiar el archivo cmake para el uso add_library(vtajni SHARED ...(y volver a compilar el código de cliente con -fPIC) que ahora sale esto:

gus@ns-l1:~/clients/customer/code/vta_jni$ nm -D /usr/java/packages/lib/libvtajni.so | grep com_
00000000113587ba T _Z44Java_com_customer_jni_JniVtaTest_vtaAnalyzeP7JNIEnv_P8_jobjectP8_jstring

Pero el nombre todavía se ha mezclado, lo que sugiere un segundo problema con el externo como se señala en los comentarios de abajo, pero la cabecera se incluye como anteriormente.

Resuelto: El calandrado se debió a una edición de depuración olvidado, que comentó a cabo la parte externo del archivo de cabecera en el proyecto C (pero el archivo generado original en el proyecto de java que me pegado encima todavía tenía que) he ahora "éxito" causado que imprima

Process finished with exit code 139 (interrupted by signal 11: SIGSEGV)
el otro tipo:

Para la función de trabajo, el nombre exacto debe presentarse con una T mayúscula en nm -D yourfile.so. Si no lo hace, usted tiene que averiguar por qué.

Aquí está un ejemplo de archivo con tres funciones que ilustra los problemas más comunes:

extern "C" {
  void correct();
  extern void notInThisSo();
}
void correct() { }

void missingJniHeader() {}

static void* dummyUsage = (void*) &notInThisSo;

Aquí está la nmsalida (ceros a la izquierda despojados):

$ gcc foo.cc -shared -o foo.so && nm -D foo.so
000010f5 T correct                     # This works
         w __cxa_finalize
         w __gmon_start__
         w _ITM_deregisterTMCloneTable
         w _ITM_registerTMCloneTable
         U notInThisSo                 # This name is believed to be in another .so
000010fc T _Z16missingJniHeaderv       # This name is C++ mangled: missing extern "C" from header

Si nada como su nombre indica arriba en nm -D, cheque nm -A yourfile.so:

$ cat bar.cc
extern "C" {
  __attribute((visibility("default"))) void visible() {}
  void not_visible() { }
}

$ gcc  -fvisibility=hidden bar.cc -shared -o bar.so  && nm -A bar.so
[...]
bar.so:000010fc t not_visible
bar.so:000010f5 T visible

Aquí se puede ver not_visibleque tiene una minúscula t, ya que la formación utilizada -fvisibility=hiddenpara ocultar el símbolo, y nada en la lista blanca de manera explícita. JNI no puede acceder a los símbolos ocultos.

(Si nm -Ada nm: bar.so: no symbols, significa que la biblioteca es despojado. Todavía se puede utilizar nm -Den las bibliotecas pelados).

Supongo que te gusta

Origin http://43.154.161.224:23101/article/api/json?id=318819&siteId=1
Recomendado
Clasificación