本文件列出了使用 NDK 时可能遇到的最常见非错误问题(部分列表)及其解决方案(如果可用)。
在较旧的 API 等级中使用 _FILE_OFFSET_BITS=64
在 统一头文件 之前,NDK 不支持 _FILE_OFFSET_BITS=64
。如果您在构建应用时定义了它,则会静默忽略它。_FILE_OFFSET_BITS=64
选项现在已支持统一头文件,但在旧版本的 Android 中,很少有 off_t
API 可作为 off64_t
变体使用。因此,在旧的 API 等级中使用此功能会导致可用函数减少。
此问题在 r16 博客文章 和 bionic 文档 中有详细说明。
问题:您的构建请求在您的 minSdkVersion
中不存在的 API。
解决方案:禁用 _FILE_OFFSET_BITS=64
或提高您的 minSdkVersion
。
未声明或隐式定义 mmap
您可能会在 C++ 中看到以下错误
error: use of undeclared identifier 'mmap'
或在 C 中看到以下错误
warning: implicit declaration of function 'mmap' is invalid in C99
使用 _FILE_OFFSET_BITS=64
指示 C 库使用 mmap64
而不是 mmap
。mmap64
直到 android-21
才可用。如果您的 minSdkVersion
值低于 21,则 C 库不包含与 _FILE_OFFSET_BITS=64
兼容的 mmap
,因此该函数不可用。
minSdkVersion
设置高于设备 API 等级
您使用 NDK 构建的 API 等级与 Java 的 compileSdkVersion
的含义大相径庭。NDK API 等级是您的应用**最低**支持的 API 等级。在 ndk-build 中,这是您的 APP_PLATFORM
设置。在 CMake 中,这是 -DANDROID_PLATFORM
。
由于对函数的引用通常是在加载库时解析的,而不是在第一次调用它们时解析的,因此您无法引用并非始终存在的 API 并使用 API 等级检查来保护其使用。如果引用了它们,则必须存在它们。
问题:您的 NDK API 等级高于您的设备支持的 API。
解决方案:将您的 NDK API 等级(APP_PLATFORM
)设置为您的应用支持的 Android 最低版本。
构建系统 | 设置 |
---|---|
ndk-build | APP_PLATFORM |
CMake | ANDROID_PLATFORM |
externalNativeBuild | android.minSdkVersion |
对于其他构建系统,请参阅 将 NDK 与其他构建系统一起使用。
无法找到 __aeabi
符号
以下消息
UnsatisfiedLinkError: dlopen failed: cannot locate symbol "
__aeabi_memcpy
"
这是一个可能的运行时错误示例。当您尝试加载本地库时,这些错误会出现在日志中。符号可能是任何__aeabi_*
;__aeabi_memcpy
和__aeabi_memclr
似乎是最常见的。
这个问题在问题126中有所记录
找不到符号rand
对于以下错误日志消息
UnsatisfiedLinkError: dlopen failed: cannot locate symbol "
rand
"
请参阅此详细的Stack Overflow解答。
未定义对__atomic_*
的引用
问题:某些ABI需要libatomic
来提供一些原子操作的实现。
解决方案:链接时添加-latomic
。
对于以下错误消息
error: undefined reference to '
__atomic_exchange_4
'
此处的实际符号可能是任何以__atomic_
为前缀的符号。
RTTI/异常无法跨库边界工作
问题:当异常跨共享库边界抛出时,不会被捕获,或者dynamic_cast
失败。
解决方案:向您的类型添加一个关键函数。关键函数是类型的第一个非纯、非内联虚函数。例如,请参阅问题533中的讨论。
《C++ ABI》指出,当且仅当两个对象的type_info
指针相同,它们才具有相同的类型。只有当捕获的type_info
与抛出的异常匹配时,才能捕获异常。dynamic_cast
也适用相同的规则。
当类型没有关键函数时,它的typeinfo
将作为弱符号发出,并且在加载库时会合并匹配的typeinfo。当在可执行文件加载后动态加载库时(换句话说,通过dlopen
或System.loadLibrary
),加载程序可能无法合并已加载库的typeinfo。发生这种情况时,这两种类型不被认为是相等的。
使用不匹配的预构建库
在您的应用程序中使用预构建库(通常是第三方库)需要额外注意。一般来说,请注意以下规则
生成的应用程序的最低API级别是所有应用程序库的
minSdkVersion
的最大值。如果您的
minSdkVersion
是16,但您正在使用针对21构建的预构建库,则生成的应用程序的最低API级别为21。如果预构建库是静态的,则不遵守此规则会在构建时显示出来,但对于预构建共享库,可能直到运行时才会出现。所有库都应使用相同的NDK版本生成。
此规则比大多数规则都灵活一些,因为中断的情况很少见,但不能保证使用不同主要版本的NDK构建的库之间的兼容性。C++ ABI 不稳定,过去曾发生过变化。
具有多个共享库的应用程序必须使用共享STL。
与不匹配的STL一样,如果非常小心,可以避免由此引起的问题,但最好避免此问题。避免此问题的最佳方法是避免在应用程序中使用多个共享库。