web-dev-qa-db-fra.com

Android NDK / JNI - référence non définie à la fonction définie dans le fichier d'en-tête personnalisé

À l'aide de JNI, j'essaie d'écrire une méthode native C++ pour le NDK Android qui effectue un appel à une fonction C définie dans un fichier d'en-tête personnalisé. Cependant, j'obtiens une erreur de référence non définie pour mon appel de fonction C.

Voici mon code C++ qui appelle la fonction C et renvoie son résultat à Java en tant que jstring:

#include <jni.h>

#include "gesture_detector.h"

JNIEXPORT jstring JNICALL Java_com_example_bmtitest_JavaAbstractionLayer_callGestureAnalysis(JNIEnv *env, jobject obj, jfloat previousX, jfloat previousY, jfloat currentX, jfloat currentY) {
    return env->NewStringUTF(gestureAnalysis(previousX, previousY, currentX, currentY));
}

Voici ma fonction C:

#include <stdio.h>

#include "gesture_detector.h"

//implemented from gesture_detector.h
const char* gestureAnalysis(float previousX, float previousY, float currentX, float currentY)
{
    float xOffset = currentX - previousX;
    float yOffset = currentY - previousY;

    if(xOffset == 0 && yOffset == 0)
    {
        return "TAP";
    }
    return "0";
}

Voici mon code Android.mk:

LOCAL_PATH := $(call my-dir)

include $(CLEAR_VARS)

LOCAL_MODULE    := gestureDetector
LOCAL_SRC_FILES := gestureDetector.c NativeAbstractionLayer.cpp
LOCAL_LDLIBS    := -landroid

include $(BUILD_SHARED_LIBRARY)

Apparemment, il semble que la définition de fonction définie dans le fichier d'en-tête personnalisé (gesture_detector.h) est introuvable. Je pense que cela peut être un problème dans mon fichier Android.mk.

Quelqu'un pourrait-il me dire ce que je fais mal ici?

20
Pink Jazz

Une erreur de "référence non définie" provient de l'éditeur de liens . Votre fichier d'en-tête ne satisfait que le compilateur.

Cependant, puisque vous mélangez C et C++, votre problème est probable nom mangling . Fondamentalement, vous devez indiquer au compilateur C++ que la fonction que vous essayez d'appeler a été créée par un compilateur C plutôt que par C++, et n'a donc pas de codes de type d'argument greffés sur son nom. À l'heure actuelle, il ne le sait pas, il essaie donc d'appeler la fonction par un nom décoré de style C++ qui diffère du nom C simple de la fonction dont l'éditeur de liens dispose réellement.

Ajoutez ceci au début de votre fichier gesture_detector.h:

#ifdef __cplusplus
extern "C" {
#endif

Et cela à la fin

#ifdef __cplusplus
}
#endif

Et faites une reconstruction propre.

Si votre véritable logique jni glue est aussi triviale que la version présentée ici, passer à une version C de celle-ci pourrait également être une option - mais attention, la syntaxe jni est différente en C et C++, donc vous ne pouvez pas simplement changer l'extension du fichier .

32
Chris Stratton

Faire simplement votre C++ natif - code entre

extern "C" {
    your code
}

Est quelque chose qui ne fonctionnera pas toujours nécessairement - comme vous pouvez le vérifier ici .

Essayez d'ajouter au fichier Android.mk:

LOCAL_ALLOW_UNDEFINED_SYMBOLS := true

Vous trouverez ici info à ce sujet.

17
Jessica Cohen