undefined reference to 'vtable for std::length_error' 问题解决

博主最近在使用NDK编译动态库时碰到一个特别奇怪的问题,我们需要调用同事给的静态库然后编译动态库,之前一直mk文件什么都是配置好了,一直也没有什么问题,在同事更新了一个库之后没有成功生成动态库,编译信息如下:

/buildbot/src/android/ndk-release-r17/external/libcxx/include/stdexcept:0: error: undefined reference to ‘vtable for std::length_error’
E:/JAVA_ANDROID/android-ndk-r17/build//…/toolchains/arm-linux-androideabi-4.9/prebuilt/windows-x86_64/lib/gcc/arm-linux-androideabi/4.9.x/…/…/…/…/arm-linux-androideabi/bin\ld: the vtable symbol may be undefined because the class is missing its key function
/buildbot/src/android/ndk-release-r17/external/libcxx/include/stdexcept:0: error: undefined reference to ‘typeinfo for std::length_error’
/buildbot/src/android/ndk-release-r17/external/libcxx/include/stdexcept:0: error: undefined reference to ‘std::length_error::~length_error()’
/buildbot/src/android/ndk-release-r17/external/libcxx/src/system_error.cpp:283: error: undefined reference to ‘std::runtime_error::~runtime_error()’
/buildbot/src/android/ndk-release-r17/external/libcxx/src/system_error.cpp:283: error: undefined reference to ‘std::runtime_error::~runtime_error()’
E:/JAVA_ANDROID/android-ndk-r17/build//…/sources/cxx-stl/llvm-libc++/libs/armeabi-v7a/libc++_static.a(system_error.o):system_error.cpp:vtable for std::__ndk1::system_error: error: undefined reference to ‘std::runtime_error::what() const’
E:/JAVA_ANDROID/android-ndk-r17/build//…/sources/cxx-stl/llvm-libc++/libs/armeabi-v7a/libc++_static.a(system_error.o):system_error.cpp:typeinfo for std::__ndk1::system_error: error: undefined reference to ‘typeinfo for std::runtime_error’
/buildbot/src/android/ndk-release-r17/external/libcxx/src/stdexcept.cpp:0: error: undefined reference to ‘vtable for std::logic_error’

出现了一堆标准库链接错误,在google上搜了一些"undefined reference to ‘vtable for std::length_error’"和"the vtable symbol may be undefined because the class is missing its key function"的答案,基本上都提到了基类作为抽象类供派生类继承使用,但是由于基类中的析构函数没有定义导致在派生类析构的时候虚函数表中找不到基类的析构函数的定义,从而导致了链接出错的问题。参考如下两个链接:
https://stackoverflow.com/questions/3065154/undefined-reference-to-vtable
https://www.cnblogs.com/johnnyflute/p/3673394.html
于是,和同事同步问题之后,一顿review代码,但是并没有发现我说的这个问题,于是博主只能继续找答案。因为看问题报的是标准库STL的问题,所以博主想的是有没有可能mk文件中的标准库链接出了问题,于是看看mk文件中这个变量的值:

LOCAL_LDLIBS
LOCAL_LDFLAGS

一般来说,LOCAL_LDLIBS是用于链接系统库,如libc,libc++_static这样的,这个标志会自动进入系统库目录中去找,且存在同名库的时候会优先选用动态库;LOCAL_LDFLAGS则是用于添加第三方库;博主的项目中需要使用到libc++abi.a和libc++_static.a两个系统静态库,但是这两个库添加到了LOCAL_LDFLAGS上了,而这个变量有一个特性,就是添加到这里的库需要注意依赖关系,即依赖库在前,被依赖库在后;于是考虑到是否是因为顺序反了导致的链接出错,做如下修改:

# LOCAL_LDFLAGS+= -L$(STL_PATH) -lc++abi -lc++_static  (注释)
LOCAL_LDFLAGS+= -L$(STL_PATH) -lc++_static -lc++abi

修改之后便顺利编译通过了。这就说明,libc++_Static.a需要依赖libcabi.a这个库,于是找了libc++abi.a这个库的一些资料,发现这个一个网站:
https://libcxxabi.llvm.org/
底下有这么一段问答:

Frequently asked questions
Q: Why are the destructors for the standard exception classes defined in libc++abi? They’re just empty, can’t they be defined inline?

A: The destructors for them live in libc++abi because they are “key” functions. The Itanium ABI describes a “key” function as the first virtual declared. And wherever the key function is defined, that is where the type_info gets defined. And in libc++ types are the same type if and only if they have the same type_info (as in there must be only one type info per type in the entire application). And on OS X, libstdc++ and libc++ share these exception types. So to be able to throw in one dylib and catch in another (a std::exception for example), there must be only one std::exception type_info in the entire app. That typeinfo gets laid down beside ~exception() in libc++abi (for both libstdc++ and libc++).
–Howard Hinnant

大意是指libc++_static中使用的一些标准库的类的析构函数的定义是在libc++abi.a中定义的,即libc++static.a需要依赖libc++abi.a库,这正好解释了博主将顺序调换一下即可正常编译的做法;
其实,这边应该将这两个库添加到LOCAL_LDLIBS上,这样不需要管添加的顺序,且是添加系统库的地方,也比较说得通;总之,这两种方案都可以解决问题。

你可能感兴趣的:(Android,开发,Android,Studio,C++,编译链接)