【问题标题】:Android ndk-build linker fails to find prebuilt library functionAndroid ndk-build 链接器找不到预建库函数
【发布时间】:2016-09-14 09:38:29
【问题描述】:

我正在尝试修改本教程以在我的 Android Studio 项目中包含一个预构建的 C 库(即不使用实验性 Gradle 插件)http://kvurd.com/blog/compiling-a-cpp-library-for-android-with-android-studio/

库本身来自一个不会透露源代码的客户,因此我无法控制构建过程的那部分,但是他们已经在遵循相同的教程。

项目构建、加载库正常工作并且 NDK 链接 (/jni/my-wrapper.c) 工作正常,直到我尝试调用我的预构建头文件中定义的实际库函数。我收到的错误是:

$ ndk-build
[arm64-v8a] Compile        : my-wrapper <= my-wrapper.c
[arm64-v8a] SharedLibrary  : libmy-wrapper.so
/Users/me/AndroidStudioProjects/MyProject/app/obj/local/arm64-v8a/objs/my-wrapper/my-wrapper.o: In function `Java_com_my_project_SignInActivity_CallFunction':
/Users/me/AndroidStudioProjects/MyProject/app/jni/my-wrapper.c:44: undefined reference to `MyFunction'
collect2: error: ld returned 1 exit status
make: *** [/Users/me/AndroidStudioProjects/MyProject/app/obj/local/arm64-v8a/libmy-wrapper.so] Error 1

这是我的 Android.mk:

LOCAL_PATH := $(call my-dir)

# static library info
include $(CLEAR_VARS)
LOCAL_MODULE := libMyLib
LOCAL_MODULE_FILENAME := libMyLib
LOCAL_SRC_FILES := ../prebuild/libMyLib.a
LOCAL_EXPORT_C_INCLUDES := ../prebuild/include
include $(PREBUILT_STATIC_LIBRARY)

# wrapper info
include $(CLEAR_VARS)
LOCAL_C_INCLUDES += ../prebuild/include
LOCAL_MODULE    := my-wrapper
LOCAL_SRC_FILES := my-wrapper.c
LOCAL_STATIC_LIBRARIES := libMyLib
include $(BUILD_SHARED_LIBRARY)

而 MyLib.h(请注意 foobar() 工作正常,因为它在标头中,但只要我从 my-wrapper.c 中调用 MyFunction,ndk-build 就会失败):

#include <math.h>
#include <setjmp.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>

int MyFunction(some stuff);
int foobar(){return 1;};

最后,my-wrapper.c:

#include <MyLib.h>

jbyte Java_com_my_project_SignInActivity_MyFunction(JNIEnv *env, jobject thiz, some other stuff){

//   return MyFunction(some other stuff which I cast to C types); //linker fails if uncommented

    return foobar(); //works fine
}

【问题讨论】:

  • 您确定 MyFunction 确实存在于库中吗?由于您无权访问源代码,因此可能值得确定。您可以使用 Android NDK 中包含的nm 工具来验证这一点。
  • nm libMyLib.a 结果为 0000458c T _Z12MyFunctionP9my_structPhS1_S1_ - 所以它看起来就在那里,除非我缺少一些微妙之处

标签: android android-ndk ndk-build


【解决方案1】:

这是一个 C++ 错误的名称。您只能在 C++ 中使用它,而不能在 C 中使用它。

如果你真的需要从 C 中调用它,你可以这样做:

extern int _Z12MyFunctionP9my_structPhS1_S1_(/* whatever the function args are */);

jbyte Java_com_my_project_SignInActivity_MyFunction(
        JNIEnv *env, jobject thiz, some other stuff) {
    return _Z12MyFunctionP9my_structPhS1_S1_(args);
}

这取决于您调用的代码是否兼容(如果是这种情况,您应该要求客户端将其 API 构建为 extern "C")。

不过,我真的建议您将代码移至 C++。

【讨论】:

  • 难以置信!客户坚持认为它是一个 C 库 - 他们是否可能错误地编译了一个 C 源代码以将名称转换为 C++,盲目地遵循kvurd.com/blog/… 的步骤 1?将包装器代码转换为 C++ 是否会对我产生任何副作用,在这种情况下,我应该回到他们那里并要求正确构建 C 库。抱歉,我不是 C++ 开发人员!
  • 原来客户端的所有 C 代码都在 .CPP 文件中,这让他们的编译器产生了混乱的名称而不是纯 C 库。
  • 是的,.cpp 文件默认会产生 C++ 错位名称。如果他们想保留 .cpp 文件但仍然保持 API C 兼容,他们只需要用 extern "C" 包装他们的函数 decls(在 #ifdef __cplusplus 内,就像 stackoverflow.com/a/67985/632035 中的最后一个 sn-p)。
猜你喜欢
  • 2017-02-05
  • 2019-09-11
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2011-11-13
  • 2018-05-16
  • 1970-01-01
  • 2023-03-20
相关资源
最近更新 更多