如何从NDK构建的静态库中解析NDK构建的静态库中的“对<myfunction>的未定义引用”?

How to resolve "undefined reference to <myfunction>" in NDK-built static library from NDK-built static library?

提问人:Alyoshak 提问时间:11/14/2015 最后编辑:Alyoshak 更新时间:11/19/2015 访问量:1182

问:

我收到一个“对'myfunction'的未定义引用,试图从共享(.so)库调用静态(.a)库中的函数。(这是 OS X 上的 NDK 问题)。该函数是名为“ffts-android”(ffts-android)的 fft 库的一部分。我能够很好地使用项目生成库。我所做的唯一更改是从 BUILD_SHARED_LIBRARY 更改为 BUILD_STATIC_LIBRARY,以便我可以将其合并到我们在组织的 Android 应用程序中使用的共享库中。

我很确定我需要的函数 ffts_init_1d(size_t, int) 应该存在于静态库中,因为我使用了 nm 实用程序(底部的输出)来列出符号表中可用的函数。

然后我想我应该尝试修改 NDK 的一个简单示例程序,以防我的 Android.mk 是问题所在。我采用了“module-exports”示例并进行了必要的最简单的更改,并得到了相同的错误。在原始状态下,它会构建一个静态库,然后将其链接到一个共享库中,就像我尝试做的那样。我只是在 Android.mk 中添加了一行,即下面的中间一行,以便它链接到我从 ffts-android 项目构建的同一库:

LOCAL_STATIC_LIBRARIES := foo
LOCAL_STATIC_LIBRARIES += libffts-neon
include $(BUILD_SHARED_LIBRARY)

然后修改了bar.c,以便它将调用我尝试调用的相同方法ffts_init_1d(size_t, int):

#include "bar.h"
#include "ffts.h"
#include "foo.h"

int  bar(int  x)
{
    /*return*/foo(x)-1;
    ffts_init_1d(1, 1);
    return 1;
}

最后,我将 ffts.h 和 libffts-neon.a 文件移动到 module-exports 可以找到它们的位置,然后构建示例。它会产生与我得到的完全相同的错误。

samples/module-exports/jni/bar/bar.c:8: undefined reference to `ffts_init_1d'

module-exports 项目和 ffts-android 项目都是纯粹的 c 代码,而我们的代码库是 c++,所以我正在尝试从 c++ 调用从 c 代码构建的静态库。但是,头文件 ffts.h 已经具有适应此标准所需的代码:

#ifdef __cplusplus
extern "C"
{

下面是 nm 实用程序的输出。在我看来,列出了我尝试调用的函数,那么为什么它不可用呢?

./nm -g libffts-neon.a

ffts.o:
         U _GLOBAL_OFFSET_TABLE_
         U __aeabi_uidiv
         U __aeabi_uidivmod
         U __aeabi_unwind_cpp_pr0
         U __aeabi_unwind_cpp_pr1
         U __android_log_print
         U __errno
         U cos
         U exit
00000000 T ffts_execute
00000000 T ffts_free
00000000 T ffts_free_1d
         U ffts_generate_func_code
00000000 T ffts_init_1d
         U ffts_init_is
         U ffts_init_offsets
         U firstpass_16_b
         U firstpass_16_f
         U firstpass_2
         U firstpass_4_b
         U firstpass_4_f
         U firstpass_8_b
         U firstpass_8_f
         U free
         U malloc
         U mprotect
         U munmap
         U perror
         U sin
         U valloc

ffts_real.o:
         U __aeabi_unwind_cpp_pr0
         U __aeabi_unwind_cpp_pr1
         U cos
00000000 T ffts_execute_1d_real
00000000 T ffts_execute_1d_real_inv
         U ffts_free
00000000 T ffts_free_1d_real
         U ffts_init_1d
00000000 T ffts_init_1d_real
         U free
         U malloc
         U sin
         U valloc
. . .

这是我在 V=1(详细输出)调用 ndk-build 时得到的结果:

MacBook-Pro:module-exports myuser$ ndk-build V=1
rm -f ./libs/arm64-v8a/lib*.so ./libs/armeabi/lib*.so ./libs/armeabi-v7a/lib*.so ./libs/armeabi-v7a-hard/lib*.so ./libs/mips/lib*.so ./libs/mips64/lib*.so ./libs/x86/lib*.so ./libs/x86_64/lib*.so
rm -f ./libs/arm64-v8a/gdbserver ./libs/armeabi/gdbserver ./libs/armeabi-v7a/gdbserver ./libs/armeabi-v7a-hard/gdbserver ./libs/mips/gdbserver ./libs/mips64/gdbserver ./libs/x86/gdbserver ./libs/x86_64/gdbserver
rm -f ./libs/arm64-v8a/gdb.setup ./libs/armeabi/gdb.setup ./libs/armeabi-v7a/gdb.setup ./libs/armeabi-v7a-hard/gdb.setup ./libs/mips/gdb.setup ./libs/mips64/gdb.setup ./libs/x86/gdb.setup ./libs/x86_64/gdb.setup
[armeabi-v7a] SharedLibrary  : libbar.so
/Users/myuser/Documents/NDKDev/android-ndk-r10e/toolchains/arm-linux-androideabi-4.8/prebuilt/darwin-x86_64/bin/arm-linux-androideabi-g++ -Wl,-soname,libbar.so -shared --sysroot=/Users/myuser/Documents/NDKDev/android-ndk-r10e/platforms/android-3/arch-arm ./obj/local/armeabi-v7a/objs/bar/bar/bar.o ./obj/local/armeabi-v7a/libfoo.a -lgcc -no-canonical-prefixes -march=armv7-a -Wl,--fix-cortex-a8  -Wl,--no-undefined -Wl,-z,noexecstack -Wl,-z,relro -Wl,-z,now -mthumb  -L/Users/myuser/Documents/NDKDev/android-ndk-r10e/platforms/android-3/arch-arm/usr/lib -llog -lc -lm -o ./obj/local/armeabi-v7a/libbar.so
jni/bar/bar.c:8: error: undefined reference to 'ffts_init_1d'
collect2: error: ld returned 1 exit status
make: *** [obj/local/armeabi-v7a/libbar.so] Error 1

这是 Android.mk 文件。略有修改,如上所述:

LOCAL_PATH := $(call my-dir)

include $(CLEAR_VARS)
LOCAL_MODULE := foo
LOCAL_SRC_FILES := foo/foo.c
LOCAL_CFLAGS := -DFOO=2
LOCAL_EXPORT_C_INCLUDES := $(LOCAL_PATH)/foo
LOCAL_EXPORT_CFLAGS := -DFOO=1
LOCAL_EXPORT_LDLIBS := -llog
include $(BUILD_STATIC_LIBRARY)

include $(CLEAR_VARS)
LOCAL_MODULE := bar
LOCAL_SRC_FILES := bar/bar.c
LOCAL_EXPORT_C_INCLUDES := $(LOCAL_PATH)/bar
LOCAL_STATIC_LIBRARIES := libffts-neon
LOCAL_STATIC_LIBRARIES += foo
include $(BUILD_SHARED_LIBRARY)
macOS android-ndk 静态库 链接器错误 未定义参考

评论

0赞 Alex Cohn 11/18/2015
显然,libffts_neon 是为 armeabi-v7a 构建的,但您的 SO 是为 armeabi 构建的。尝试,以相同的最小 Android.mk,也许会有所帮助。ndk-build APP_ABI=armeabi-v7a
0赞 Alyoshak 11/18/2015
同样的错误。Application.mk 是为 ALL 定义的,因此它确实试图构建一些行不通的组合。但是我按照您的指示对其进行了定义,仅适用于 armeabi-v7a,并得到了相同的错误。需要明确的是,我正在构建模块导出示例,并按照问题进行修改。仅供参考,该示例在其 objs/local/armeabi-v7a 文件夹中构建了其 .a 库,因此这就是我放置 libffts-neon.a 文件的位置。
0赞 Alyoshak 11/18/2015
有趣。刚刚注意到错误消息确实略有变化。在它是 samples/module-exports/jni/bar/bar.c:8:对“ffts_init_1d”的未定义引用之前。重新定义APP_ABI后,它现在是 jni/bar/bar.c:8:错误:未定义对“ffts_init_1d”的引用
0赞 Alex Cohn 11/18/2015
也许它没有在正确的目录中寻找库?在此处(或 pastebin)运行并粘贴控制台输出ndk-build V=1
1赞 Alyoshak 11/19/2015
成功了。非常感谢。想提供一个我可以选择正确的答案吗?一个问题:您发送的文档让我对使用什么/如何使用LOCAL_MODULE的问题感到困惑。我通过在新的预构建部分中使用“my-ffts”,然后在构建共享库的最后一部分将“my-ffts”分配给 LOCAL_STATIC-LIBRARIES 来让它工作。但是在 V=1 输出中没有提到“my-ffts”。LOCAL_MODULE有什么用?只是为了在 .mk 文件中提供重命名?

答:

2赞 Alex Cohn 11/19/2015 #1

您必须定义预构建的静态库 libffts-neon.a 才能使用您的模块。这个想法是,每个库(静态的或共享的,预构建的或编译的)都应该有其单独的部分,并被分配其单独的LOCAL_MODULE名称。所以,你错过了以下结界:

include $(CLEAR_VARS)
LOCAL_MODULE := libffts-neon
LOCAL_SRC_FILES := obj/local/armeabi-v7a/libffts-neon.a
include $(PREBUILT_STATIC_LIBRARY)

它可以放置在 Android.mk 中的任何位置,或者使用 include 指令并将其保存为单独的文件。

请注意,LOCAL_STATIC_LIBRARIES引用的是模块名称,而不是实际文件的名称。因此,以下操作也可以:

include $(CLEAR_VARS)
LOCAL_MODULE := qqq
LOCAL_SRC_FILES := obj/local/armeabi-v7a/libffts-neon.a
include $(PREBUILT_STATIC_LIBRARY)
…
LOCAL_STATIC_LIBRARIES += qqq
include $(BUILD_SHARED_LIBRARY)

另外需要注意的是,你可以把你预构建的库放在任何地方,ndk-build会根据需要将其复制到相应的目录。

官方文档出奇地详细,并解决了多 ABI 支持和预构建库的其他黑暗角落的问题。