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

时间:2018-12-14 18:48:43

标签: android android-ndk libm

我正在移植一个C和C ++库,该库当前可在iOS上使用,并可以在Android应用程序上使用。我归结为最后三个链接器错误(出于隐私原因而混淆):

/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:错误:未定义对“小室”的引用

现在,我知道这些通常来自与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 T cpow s_cpowf.o: 00000000 T cpowf s_cpowl.o: 00000000 T cpowl

不一致令人困惑。如果不支持,是否应该从标头中完全丢失它?为什么静态库没有动态库,而动态库没有?

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

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

1 个答案:

答案 0 :(得分:1)

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

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

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

  

此外,即使在api 22上,它也会在静态库中显示

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

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

  

不一致令人困惑。如果不支持,是否应该从标头中完全丢失它?为什么静态库没有动态库,而动态库没有?

标头具有一个ifdef保护器,可以将其隐藏:https://android.googlesource.com/platform/prebuilts/ndk/+/dev/platform/sysroot/usr/include/complex.h#237

如果对这些函数进行了声明,并且认为您正在为API 22进行构建,则您的构建系统有问题。

  

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

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

使用libc.a构建仅适用于独立的可执行文件(例如strace和gdbserver),而不适用于应用程序,即使只有不需要联网的情况下,也是如此。

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