我正在移植一个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/)或仅是我正在使用的这三个函数。
答案 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静态链接到您的应用程序应该没问题。