在使用 API 级别 22 中使用来自 <complex.h> 的函数时出现链接错误
Linking errors when using functions from <complex.h> in using API level 22
我正在移植目前在 iOS 上运行的 C 和 C++ 库,以便在 Android 应用程序上使用。我归结为最后 3 个 linker 错误(出于隐私原因混淆):
/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: 错误:未定义对 'cabs'
的引用
现在我知道这些通常来自 linking 和 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
这种不一致令人费解。如果不支持,它不应该从 header 中完全消失吗?为什么静态库有而动态库没有?
静态地 link 反对它有意义吗?如果是这样,考虑到当前 api 版本的正确路径,我该怎么做?
我的另一个选择似乎是窃取 libm 的实现(比如 http://openlibm.org/)或者我正在使用的这 3 个函数。
tl;dr:是的,静态 linking 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 构建。如果你要静态 link 一些东西,那么使用旧的东西是没有意义的。
它(实际上只有一个版本的 libc.a/libm.a 每个 ABI)被复制到每个 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 的大部分网络实际上被分派给 netd,并且 libc 和 netd 之间的协议在过去发生了变化(不幸的是不是版本协议)。
使用 libc.a 构建仅适用于独立的可执行文件(想想 strace 和 gdbserver)而不是应用程序,即使那样也只有在您不需要网络时才可行。
也就是说,libm.a要简单得多。使 libc.a 无法用于应用程序的复杂交互不会影响 libm。只有当编译器以某种方式无法内联操作时,您才会真正在 libm 中结束 运行 代码。静态 linking libm.a 到您的应用程序应该没问题。
我正在移植目前在 iOS 上运行的 C 和 C++ 库,以便在 Android 应用程序上使用。我归结为最后 3 个 linker 错误(出于隐私原因混淆):
/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: 错误:未定义对 'cabs'
的引用现在我知道这些通常来自 linking 和 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
这种不一致令人费解。如果不支持,它不应该从 header 中完全消失吗?为什么静态库有而动态库没有?
静态地 link 反对它有意义吗?如果是这样,考虑到当前 api 版本的正确路径,我该怎么做?
我的另一个选择似乎是窃取 libm 的实现(比如 http://openlibm.org/)或者我正在使用的这 3 个函数。
tl;dr:是的,静态 linking libm.a 应该没问题
检查 libm.map.txt 文件:https://android.googlesource.com/platform/bionic/+/master/libm/libm.map.txt#289
这些功能直到 O.
才添加到 AndroidAlso, in the static library it does show, even on api 22
静态库不是 API 22 静态库。它实际上是 AOSP 的 ToT 构建。如果你要静态 link 一些东西,那么使用旧的东西是没有意义的。
它(实际上只有一个版本的 libc.a/libm.a 每个 ABI)被复制到每个 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 的大部分网络实际上被分派给 netd,并且 libc 和 netd 之间的协议在过去发生了变化(不幸的是不是版本协议)。
使用 libc.a 构建仅适用于独立的可执行文件(想想 strace 和 gdbserver)而不是应用程序,即使那样也只有在您不需要网络时才可行。
也就是说,libm.a要简单得多。使 libc.a 无法用于应用程序的复杂交互不会影响 libm。只有当编译器以某种方式无法内联操作时,您才会真正在 libm 中结束 运行 代码。静态 linking libm.a 到您的应用程序应该没问题。