2012-02-20 9 views
6

Estoy tratando de usar JNI y obtener java.lang.UnsatisfiedLinkError. A diferencia de las otras millones de preguntas que se hacen al respecto, tengo la lib en mi camino e incluso he visto cambiar la excepción cuando la elimino. Estoy seguro de que algo está mal con el dll que he creado, pero no estoy seguro de qué.JNI: la biblioteca se encuentra en la ruta, pero el método no es (java.lang.UnsatisfiedLinkError)

Aquí está mi código de clase Java:

package com; 

public class Tune { 
    static { 
     System.loadLibrary("lala"); 
    } 
    public static void main(String[] args) { 
     Tune j = new Tune(); 
     System.out.println("2+6="+j.add(2, 6)); 
    } 
    native public int add(int x,int y); 
} 

Aquí es la parte abreviada de mi javah archivo de cabecera producido:

/* 
* Class:  com_Tune 
* Method: add 
* Signature: (II)I 
*/ 
JNIEXPORT jint JNICALL Java_com_Tune_add 
    (JNIEnv *, jobject, jint, jint); 

Aquí está mi código C++:

#include <jni.h> 
#include <com_Tune.h> 

JNIEXPORT jint JNICALL Java_com_Tune_add 
    (JNIEnv * env, jobject obj, jint x, jint y) { 
    return x+y; 
    } 

Aquí está la excepción de tiempo de ejecución que recibo de eclipse:

Exception in thread "main" java.lang.UnsatisfiedLinkError: com.Tune.add(II)I 
    at com.Tune.add(Native Method) 
    at com.Tune.main(Tune.java:9) 

He leído que la excepción anterior significa que encontró la biblioteca "lala", pero que el método "agregar" todavía no está definido. Las únicas cosas que veo diferente entre mi proyecto y el tutorial son:

  • mina usa un paquete, en lugar del paquete por defecto (no deben tutoriales realmente hacer esto vamos vamos profesional?!?!)
    • La mina tiene un valor de retorno.
    • Moví DLL después de su creación (no creo que esto va a romper ya está configurado mi camino.)

¿Cómo es esto posible?

Otra Info:

SO: Windows 7
JDK: 1.6.0_31 (para x86, JVM de 32 bits)
C++ IDE: Code :: Blocks (se compiló el DLL automáticamente por el Código :: Blocks IDE)
C++ compilador: MinGW32-g ++ (la GNU C++ compilador)

tengo jni.h y com_Tune.h en C: \ _ \ incluir
I tienen lala.dll en C: \ _ \ lib

Variables de entorno:
RUTA: C: \ Archivos de programa (x86) \ NVIDIA Corporation \ PhysX \ Common;% CommonProgramFiles% \ Microsoft Shared \ Windows Live; C: \ Archivos de programa (x86) \ AMD APP \ bin \ x86_64; C : \ Archivos de programa (x86) \ AMD APP \ bin \ x86;% SystemRoot% \ system32;% SystemRoot%;% SystemRoot% \ System32 \ Wbem;% SYSTEMROOT% \ System32 \ WindowsPowerShell \ v1.0 \; C: \ Program Archivos (x86) \ ATI Technologies \ ATI.ACE \ Core-Static; C: \ Apps;% JAVA_HOME% \ bin; C: \ Archivos de programa \ MySQL \ MySQL Server 5.5 \ bin;% MAVEN_HOME% \ bin;% HADOOP_INSTALL% \ bin; c: \ Archivos de programa (x86) \ Microsoft SQL Server \ 100 \ Tools \ Binn \; c: \ Archivos de programa \ Microsoft SQL Server \ 100 \ Tools \ Binn \; c: \ Archivos de programa \ Microsoft SQL Server \ 100 \ DTS \ Binn \; C: \ MinGW \ bin; C: \ Archivos de programa (x86) \ GnuWin32 \ bin; C: _ \ ruta; C: \ _ \ lib; C: \ Archivos de programa (x86) \ Microsoft Visual Studio 10.0 \ VC \ bin; C: \ _ \ include

+0

el código parece correcto. ¿Podría verificar la tabla de exportación de DLL (es decir, con Dependency Walker) y asegurarse de que su función esté presente en las exportaciones? – Mersenne

Respuesta

1

sólo una suposición ... Es el DLL depende de otro DLL que no está en el camino? Los módulos MinGW generalmente dependen de una biblioteca de tiempo de ejecución de C específica.

+0

bien, estoy intentando su consejo para usar Dependency walker. Desafortunadamente soy nuevo en C++, y esta es la primera vez que oigo sobre el caminante de la dependencia. No estoy seguro de cómo usarlo para detectar dependencias faltantes. Abrí "lala.dll" con él, y seleccioné el nodo raíz en el árbol. La tabla "Pi" está vacía. La tabla "E" tiene una entrada para una función. Función: Java_com_Tune_add @ 16. Ordinal: 1 (0x0 0 0 1). Sugerencia: 0 (0x0 0 0 0). Punto de entrada: 0x0 0 0 0 1 2 5 4. ¿Puede decirme qué debería buscar? – msknapp

+0

Además, la columna "E" tiene un bloque con la letra "C" en él, no "C++". ¿Podría ser el problema? – msknapp

+0

Sí, eso es todo. Su función se exporta. La marca "C" es normal, "C++" marca los métodos de las clases de C++, como sé. Mire hijos directos del nodo raíz. Eso es bibliotecas importadas. ¿Qué hay exactamente? Para su caso "just-simple-method-library" debe haber pocas entradas. Es decir. en mi DLL de prueba (también con un método simple) solo hay dos bibliotecas. – Mersenne

2

Una posible fuente del problema Lem podría ser que usted compiló el código usando un compilador de C++, que usa una [convención de llamadas] diferente que la C.Si ése es el caso, entonces la solución sería la de envolver el código para el método en un bloque extern "C" así:

#ifdef __cplusplus 
extern "C" { 
#endif 

JNIEXPORT jint JNICALL Java_com_Tune_add 
... 

#ifdef __cplusplus 
} 
#endif 
+0

gracias por intentar ayudar, pero desafortunadamente no lo solucionó. – msknapp

+0

Creo que msknapp ha omitido las directivas de preprocesador en su pregunta. 'javah', la herramienta que genera encabezados para JNI, agrega cosas necesarias automáticamente. – Mersenne

+0

Como dije en la pregunta, la salida de javah fue abreviada para mantener la pregunta corta. No cambié nada de lo que fuera javah. Si realmente quieres ver todo, aquí van:/* NO editar este archivo - se genera la máquina */#include /* Cabecera de com_Tune clase */ #ifndef _Included_com_Tune #define _Included_com_Tune #ifdef __cplusplus extern "C" { #endif /* * Clase: com_Tune * Método: añadir * Firma: me */ JNIEXPORT jint JNICALL Java_com_Tune_add (JNIEnv *, jobject, jint (II) , jint); #ifdef __cplusplus } #endif #endif – msknapp

4

el problema es con el nombre del compilador ha generado: [email protected]

utilizar dos

gcc -Wl,-kill-at

O

gcc -Wl,--add-stdcall-alias

Esto se asegurará de generación de Java_com_Tune_add

Y luego su llamada al método será exitosa.

+0

Para la nota adicional, esta respuesta es la respuesta correcta y esto solucionó mi problema. Creo que esta es la respuesta que debe ser aceptada. En cambio, otros que cavan en este hilo más tarde confundirán. –

0

Tuve el mismo problema y la bandera -Wl, -kill-at funcionó para mí.

0

Tratar con el ejemplo siguiente para Windows:

class P 
{ 
    static 
    { 
    // "P" is the name of DLL without ".dll" 
    System.loadLibrary ("P"); 
    } 

    public static native void f(int i); 

    public static void main(String[] args) 
    { 
    f(1); 
    } 
} 
:

Paso 1. Cree el siguiente archivo Java (P.java) (recordemos que el nombre de la clase Java debe ser el mismo que el nombre del archivo correspondiente)

Paso 2. javac P.java

Paso 3. javah P

Entonces, "javah" genera el archivo de cabecera "Ph"

Paso 4. Crear el archivo "P.Def", incluyendo las dos líneas siguientes (este archivo define los símbolos exportados, en este caso el nombre de la función C):

EXPORTS 
Java_P_f 

Paso 5. Crear su archivo C (Pc):

#include "P.h" 

JNIEXPORT void JNICALL Java_P_f(JNIEnv *env, jclass c, jint i) 
{ 
    printf("%i\n",i); 
} 

Paso 6. Dentro de Visual Studio comando promt, definir las siguientes variables:

conjunto JAVA_HOME = el camino de JDK

sistema incluye =% include%;% JAVA_HOME% \ include;% JAVA_HOME% \ incluir \ win32

Paso 7. Generar DLL:

cl/LD Pc P.Def

Paso 8 . Ejecutar el programa Java:

java P

(Nota: P.dll y P.class se encuentran en el mismo directorio)

Cuestiones relacionadas