android - 使用 API 级别 22 使用 <complex.h> 中的函数时出现链接错误

标签 android android-ndk libm

我正在移植一个当前在 iOS 上运行的 C 和 C++ 库,以便在 Android 应用程序上使用。我归结为最后 3 个链接器错误(出于隐私原因进行了模糊处理):

/Users/fer662/projects/xxx/jni/xxx_preprocessing.c:10184: 错误:未定义对“cexp”的引用 /Users/fer662/projects/xxx/jni/xxx_preprocessing.c:10184: 错误:未定义对“cpowf”的引用 /Users/fer662/projects/xxx/jni/xxx_preprocessing.c:10285: error: undefined reference to 'cabs'

现在我明白这些通常来自与 libm.so (-lm) 的链接,但我已经在这样做了。如果我去用 nm 检查违规情况:

nm -g/Users/fer662/Library/Android/sdk/ndk-bundle/platforms/android-22/arch-x86/usr/lib/libm.so | grep cpow

什么都没有回来。无论如何,如果我使用 api 28

nm -g  /Users/fer662/Library/Android/sdk/ndk-bundle/platforms/android-28/arch-x86/usr/lib/libm.so | grep cpow
00003900 T cpow
00003910 T cpowf
00003920 T cpowl

此外,在静态库中它确实显示,即使在 api 22 上也是如此:

nm -g/Users/fer662/Library/Android/sdk/ndk-bundle/platforms/android-22/arch-x86/usr/lib/libm.a | grep cpow s_cpow.o: 00000000 Tcpow s_cpowf.o: 00000000 T cpowf s_cpowl.o: 00000000 T cpowl

这种不一致令人费解。如果不支持,它不应该从标题中完全丢失吗?为什么静态库有它而动态库没有?

静态链接是否有意义?如果是这样,考虑到当前 api 版本的正确路径,我该怎么做?

我的另一个选择似乎是窃取 libm 的一个实现(比如 http://openlibm.org/ )或者我正在使用的这 3 个函数。

最佳答案

tl;dr:是的,静态链接 libm.a 应该没问题

检查 libm.map.txt 文件:https://android.googlesource.com/platform/bionic/+/master/libm/libm.map.txt#289

这些功能直到 O 才被添加到 Android 中。

Also, in the static library it does show, even on api 22

静态库不是 API 22 静态库。它实际上是 AOSP 的 ToT 构建。如果您要静态链接某些内容,则没有必要使用旧内容。

它(实际上每个 ABI 只有一个版本的 libc.a/libm.a)被复制到每个 API 目录中的原因是因为为旧 NDK 制作的构建系统需要它。如果您查看 r19 中的统一工具链 (toolchains/llvm/prebuilts/$HOST),您会发现每个 ABI 只有一个副本。

The inconsistency is puzzling. Shouldn't it be missing from the header altogether if not supported? Why does the static lib have it and the dylib not?

header 有一个隐藏它的 ifdef 守卫:https://android.googlesource.com/platform/prebuilts/ndk/+/dev/platform/sysroot/usr/include/complex.h#237

如果您有这些函数的声明并且您认为您正在为 API 22 构建,那么您的构建系统有问题。

Would it make sense to statically link against it? And if so, how would I do it, taking into account the right path for the current api version?

一般来说,对于这类问题,这不是一个好的解决方案,因为 Zygote 已经加载了一个 libc,加载另一个 libc 可能会导致各种问题,因为它们可能会发生冲突。此外,libc 的大部分网络实际上被分派(dispatch)给 netd,并且 libc 和 netd 之间的协议(protocol)在过去发生了变化(不幸的是不是版本协议(protocol))。

使用 libc.a 构建仅适用于独立的可执行文件(想想 strace 和 gdbserver)而不是应用程序,即使那样也只有在您不需要网络时才可行。

也就是说,libm.a 要简单得多。使 libc.a 无法用于应用程序的复杂交互不会影响 libm。只有当编译器以某种方式无法内联操作时,您才会真正在 libm 中运行代码。将 libm.a 静态链接到您的应用程序应该没问题。

关于android - 使用 API 级别 22 使用 <complex.h> 中的函数时出现链接错误,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/53785338/

相关文章:

android - 无法连接到 Android 模拟器 Windows 操作系统上的开发服务器?

java - 使用 flexjson 序列化对象

c++ - 为什么链接器找不到我在类中声明的模板函数?

android - 如何保护 Android 应用程序中的字符串?

c - 什么是 libc?它包括哪些功能?我们怎样才能得到它的源代码?

c++ - 为什么它不需要链接库?

android - 从图库中选择图像

android - executePendingTransactions 的递归入口( fragment 内没有 fragment )

android - 在 Android Studio (cmake) 中使用预构建的共享库