Android NDK / JNI - 在自定义头文件中定义的函数未定义引用

21

使用JNI,我正在尝试编写一个本地的C++方法,用于Android NDK中调用在自定义头文件中定义的C函数。 但是,我得到了我的C函数调用的未定义引用错误。

这是我的C++代码,它调用C函数并将其结果作为jstring返回给Java:

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

这是我的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";
}

这是我的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)

看起来自定义头文件(gesture_detector.h)中定义的函数定义找不到了。我认为这可能是我的 Android.mk 文件的问题。

有人能告诉我我在这里做错了什么吗?

3个回答

36
"undefined reference" 错误来自于连接器。你的头文件只满足了编译器。但是,由于你正在混合使用C和C ++,你的问题很可能是name mangling。基本上,你需要告诉C++编译器你试图调用的函数是由C编译器创建的,而不是C ++编译器创建的,因此它没有将参数类型代码嵌入其名称中。现在它不知道这一点,因此正在尝试通过一个C ++风格的装饰名称来调用该函数,而这个名称与连接器实际可用的函数的纯C名称不同。请在gesture_detector.h文件的开头添加以下内容:
#ifdef __cplusplus
extern "C" {
#endif

并且这是在结尾处

#ifdef __cplusplus
}
#endif

请进行干净的重建。

如果您的真实jni粘合逻辑与此处呈现的版本一样简单,那么切换到C版本也是一个选择 - 但请注意,jni语法在C和C ++中不同,因此您不能仅更改文件扩展名。


是的,你的答案非常正确! - Goran Horia Mihail

19

只需在代码之间执行您的本地C++代码即可

extern "C" {
    your code
}

并不是所有的东西都一定能正常工作 - 可以在这里查看。

尝试在Android.mk文件中添加以下内容:

LOCAL_ALLOW_UNDEFINED_SYMBOLS := true

在这里你可以找到更多关于它的信息


2
也许可以,但有风险。这将掩盖问题直到运行时。但如果在那时无法解决,程序将崩溃。 - Chris Stratton
@ChrisStratton - 感谢您的评论。还有其他建议吗? - Jessica Cohen
1
是的,考虑到 C/C++ 的分裂,这很可能是一个名称混淆问题。 - Chris Stratton
1
缺少什么.so文件?找不到的函数不在库中,而是在正在构建的文件中。请不要只是借鉴其他来源的答案,而没有花时间去了解它们是否适用。 - Chris Stratton
@ChrisStratton - 好的,我现在明白了。谢谢!我刚刚编辑了我的答案。 - Jessica Cohen

1
在我的项目中,构建一切正常,但在我添加了两个新文件somefile.h和somefile.c之后,开始出现“未定义的引用”错误。我将这些文件添加到我已经构建的现有库的源目录中,因此在引用新文件时不需要更改cmake。清理并重新构建项目没有起作用。但是,我在CMakeLists.txt文件中进行了一些冗余更改,然后进行了清理重建。构建成功了。之后,我删除了这个更改(因为它是多余的),再次尝试进行清理重建,代码可以工作了。也许构建系统正在从缓存中获取某些对象,而更改CMakeLists.txt强制它从头开始构建这些对象。如果有人知道为什么会出现这种行为,请告诉我。谢谢!

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接