JNI: la bibliothèque est trouvée sur le chemin, mais la méthode ne l'est pas (java.lang.UnsatisfiedLinkError)

StackOverflow https://stackoverflow.com/questions/9367700

Question

J'essaye d'utiliser JNI et j'obtiens java.lang.UnsatisfiedLinkError. Contrairement aux millions de questions posées à ce sujet, j'ai la bibliothèque sur mon chemin, et j'ai même vu l'exception changer lorsque je la supprime. Je suis sûr que quelque chose ne va pas avec la DLL que j'ai créée, mais je ne sais pas quoi.

Voici mon code de classe 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);
}

Voici la partie abrégée de mon fichier d'en-tête produit par javah:

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

Voici mon code 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;
  }

Voici l'exception d'exécution que j'obtiens avec 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)

J'ai lu que l'exception ci-dessus signifie qu'il a trouvé la bibliothèque "lala", mais que la méthode "add" n'est toujours pas définie. Les seules choses que je vois différentes entre mon projet et le tutoriel sont:

  • Le mien utilise un package, au lieu du package par défaut (les didacticiels ne devraient-ils pas vraiment faire cela?!?! allons devenir professionnel)
    • Le mien a une valeur de retour.
    • J'ai déplacé ma dll après sa création (je ne pense pas que cela la cassera puisque mon chemin est configuré.)

Comment est-ce possible?

Autres informations:

Système d'exploitation: Windows 7
JDK: 1.6.0_31 (pour x86, jvm 32 bits)
C ++ IDE: Code :: Blocks (la dll a été compilée automatiquement par l'IDE Code :: Blocks)
Compilateur C ++: MinGW32-g ++ (le compilateur GNU C ++)

J'ai jni.h et com_Tune.h dans C: \ _ \ include
J'ai lala.dll dans C: \ _ \ lib

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

Était-ce utile?

La solution

Juste deviner ... Votre dll dépend-elle d'une autre dll qui n'est pas sur le chemin?Les modules MinGW dépendent généralement d'une bibliothèque d'exécution C spécifique.

Autres conseils

Le problème vient du nom que le compilateur a généré: Java_com_Tune_add@16

Utilisez l'un des deux

gcc -Wl,-kill-at

Ou

gcc -Wl,--add-stdcall-alias

Cela garantira la génération de Java_com_Tune_add

Et puis votre appel de méthode réussira.

Une source possible du problème pourrait être que vous avez compilé le code en utilisant un compilateur C ++, qui utilise une [convention d'appel] différente de celle du C. Si tel est le cas, la solution serait d'encapsuler le code de la méthode dansun bloc extern "C" comme celui-ci:

#ifdef __cplusplus
extern "C" {
#endif

JNIEXPORT jint JNICALL Java_com_Tune_add
...

#ifdef __cplusplus
}
#endif

J'ai eu le même problème et le drapeau -Wl, -kill-at a fonctionné pour moi.

Essayez avec l'exemple suivant pour Windows: (rappelez-vous que le nom de la classe Java doit être le même que le nom de fichier correspondant)

Étape 1. Créez le fichier Java suivant (P.java):

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

Étape 2. javac P.java

Étape 3. javah P

Ensuite, "javah" génère le fichier d'en-tête "P.h"

Étape 4. Créez le fichier "P.def" comprenant les deux lignes suivantes (ce fichier définit les symboles exportés, dans ce cas le nom de la fonction C):

EXPORTS
Java_P_f

Étape 5. Créez votre fichier C (P.c):

#include "P.h"

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

Étape 6. Dans l'invite de commande Visual Studio, définissez les variables suivantes:

set JAVA_HOME= le chemin du JDK

set include=% include%;% JAVA_HOME% \ include;% JAVA_HOME% \ include \ win32

Étape 7. Générer la DLL:

cl / LD P.c P.def

Étape 8. Exécutez le programme Java:

java P

(Remarque: P.dll et P.class se trouvent dans le même répertoire)

Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top