NDK编译系列:常见报错问题解决
本文小结NDK编译过程中遇到的高频问题分析与解决方法。
报错:ld: error: undefined symbol XXX referenced by XX.c
编动态库阶段:
-
可能原因
- 原因1:c/cpp代码混写,纯c代码在头文件声明中未加extern c
- 原因2:相关依赖的库未预加载进来
- 原因3:未正确包含相关头文件
- 原因4:头文件函数声明形参、库文件实现以及调用处传参是否一致
-
解决方式
- 原因1:在相关纯C代码头文件函数声明中,首尾添加:
#ifdef __cplusplus extern "C" { #endif /* ... */ #ifdef __cplusplus } #endif
- 原因2:
- 一般是生成动态库时,还依赖其他库的场景,需先将相关库装载进编译空间
- 若报错
undefined symbol: std::__ndk1::cout
,cout无法识别,则表示stl标准库未加载进来链接,application.mk完成 - 若报错显示非标准库的依赖符号未定义,则需要预加载非标准库,andriod.mk完成
- 原因3:
- 在Android.mk中添加头文件索引目录,如:
LOCAL_C_INCLUDES += $(LOCAL_PATH)/include
LOCAL_C_INCLUDES += ./include
- 原因4:
- 确保头文件函数声明形参、库文件实现以及调用处传参一致
预加载相关库来编译当前库
可以预加载静态库或动态库,预加载的原因是提前告诉当前这个库,在运行时到底依赖哪个库。
预加载非标准库
在Andriod.mk完成,链接所依赖的非标准库:
include $(CLEAR_VARS)
LOCAL_MODULE := libso1
LOCAL_SRC_FILES := $(LOCAL_PATH)/lib/lib1.so
include $(PREBUILT_SHARED_LIBRARY)
#include $(PREBUILT_STATIC_LIBRARY)
include $(CLEAR_VARS)
LOCAL_MODULE := libso2
LOCAL_SRC_FILES := $(LOCAL_PATH)/lib/lib2.so
include $(PREBUILT_SHARED_LIBRARY)
include $(CLEAR_VARS)
LOCAL_MODULE := liba1
LOCAL_SRC_FILES := $(LOCAL_PATH)/lib/lib1.a
include $(PREBUILT_STATIC_LIBRARY)
LOCAL_SHARED_LIBRARIES := libso1 libso2 # 链接依赖的动态库
LOCAL_STATIC_LIBRARIES := liba1 # 链接依赖的静态库
预加载标准库
在Application.mk完成,以下指令二选一
APP_STL := c++_shared # 使用stl动态库,需同步将标准库放同目录中,减小内存
APP_STL := c++_static # 使用stl静态库,直接将标准库嵌入到so库中,增大内存
编可执行文件阶段
与上面的处理方式类似,也需要提前预加载相应的依赖库,NDK已通过PREBUILT_STATIC_LIBRARY等方式预加载进来,不用再在LDFLAG中去链接添加库。
问题:为啥LOCAL_PATH不是当前工作目录而是NDK安装目录?
详细报错信息:
make: No rule to make target ‘D:/ProgramData/android-ndk-r23c/build//…/build/core/./src/*.c’, needed by ‘D:/workspace/ndk_project/build_exe/obj/local/arm64-v8a/objs/DEMO/./src/main.o’. Stop.
原因分析:
- mk文件中,LOCAL_PATH宏变量必须在第一行,且后续不必反复声明
- CLEAR_VARS清理本地变量时,不会清理到LOCAL_PATH
LOCAL_PATH := $(call my-dir) # 需在首行才能生效,且后序不用反复调用
include $(CLEAR_VARS) # 运行变量清理宏
$(info "$(LOCAL_PATH )") # 打印LOCAL_PATH变量内容,未被清理
具体使用方法见NDK的官方指导文档:Andriod.mk。