在 Ubuntu 20.04 上使用 boost-thread 出现 Clang 10 链接错误

问题描述

在使用 clang/lld 7 从 Ubuntu 18.04 升级并使用 clang/lld 10 和 boost 1.71 将 1.65 升级到 20.04 后,我遇到了一个我不知道如何解决链接错误。 Ubuntu 20.04 上的 clang 和 boost 是不兼容的对吗?我有哪些选择可以使用 clang 在 Ubuntu 20.04 上进行编译?

错误的最小例子是

#include <boost/thread/shared_mutex.hpp>
int main() {
  boost::shared_mutex sm;
}

注意事项:

我创建了一个可以在 ubuntu 20.04 系统或容器中轻松复制的最小示例,为了复制,我使用了来自 dockerhub 的普通 ubuntu:focal 容器。

  1. 安装 clang/lld 10 并提升 1.71
apt update && apt install clang lld libboost-thread-dev
update-alternatives --install "/usr/bin/ld" "ld" "/usr/bin/ld.lld-10" 30

现在所有要求都已安装,LLD 是链接器。

  1. 创建最小的示例并编译/链接
root@d66452260792:/# cat x.cpp 
#include <boost/thread/shared_mutex.hpp>
int main() {
  boost::shared_mutex sm;
}

root@d66452260792:/# clang -lboost_thread x.cpp
  1. 预期结果:
successful compilation
  1. 实际结果
  • 使用 BFD 链接器 (GNU ld 2.34):
/usr/bin/ld: /tmp/x-a145e4.o: undefined reference to symbol '_ZTVN10__cxxabiv121__vmi_class_type_infoE@@CXXABI_1.3'
/usr/bin/ld: /lib/x86_64-linux-gnu/libstdc++.so.6: error adding symbols: DSO missing from command line
clang: error: linker command Failed with exit code 1 (use -v to see invocation)
ld: error: undefined symbol: std::allocator<char>::allocator()
>>> referenced by x.cpp
>>>               /tmp/x-dd4c59.o:(boost::system::detail::generic_error_category_message[abi:cxx11](int))

ld: error: undefined symbol: std::__cxx11::basic_string<char,std::char_traits<char>,std::allocator<char> >::basic_string(char const*,std::allocator<char> const&)
>>> referenced by x.cpp
>>>               /tmp/x-dd4c59.o:(boost::system::detail::generic_error_category_message[abi:cxx11](int))

ld: error: undefined symbol: std::allocator<char>::~allocator()
>>> referenced by x.cpp
>>>               /tmp/x-dd4c59.o:(boost::system::detail::generic_error_category_message[abi:cxx11](int))
>>> referenced by x.cpp
>>>               /tmp/x-dd4c59.o:(boost::system::detail::generic_error_category_message[abi:cxx11](int))

ld: error: undefined symbol: std::_V2::generic_category()
>>> referenced by x.cpp
>>>               /tmp/x-dd4c59.o:(boost::system::detail::std_category::equivalent(int,std::error_condition const&) const)
>>> referenced by x.cpp
>>>               /tmp/x-dd4c59.o:(boost::system::detail::std_category::equivalent(std::error_code const&,int) const)
>>> referenced by x.cpp
>>>               /tmp/x-dd4c59.o:(boost::system::detail::std_category::equivalent(std::error_code const&,int) const)

ld: error: undefined symbol: typeinfo for std::_V2::error_category
>>> referenced by x.cpp
>>>               /tmp/x-dd4c59.o:(boost::system::detail::std_category::equivalent(int,int) const)
>>> referenced by x.cpp
>>>               /tmp/x-dd4c59.o:(typeinfo for boost::system::detail::std_category)

ld: error: undefined symbol: __dynamic_cast
>>> referenced by x.cpp
>>>               /tmp/x-dd4c59.o:(boost::system::detail::std_category::equivalent(int,int) const)

ld: error: undefined symbol: __cxa_begin_catch
>>> referenced by x.cpp
>>>               /tmp/x-dd4c59.o:(__clang_call_terminate)
>>> referenced by x.cpp
>>>               /tmp/x-dd4c59.o:(boost::system::system_error::what() const)
>>> referenced by x.cpp
>>>               /tmp/x-dd4c59.o:(boost::system::error_category::message(int,char*,unsigned long) const)
>>> referenced by x.cpp
>>>               /tmp/x-dd4c59.o:(void std::_Rb_tree<boost::system::error_category const*,std::pair<boost::system::error_category const* const,std::unique_ptr<boost::system::detail::std_category,std::default_delete<boost::system::detail::std_category> > >,std::_Select1st<std::pair<boost::system::error_category const* const,std::default_delete<boost::system::detail::std_category> > > >,boost::system::detail::cat_ptr_less,std::allocator<std::pair<boost::system::error_category const* const,std::default_delete<boost::system::detail::std_category> > > > >::_M_construct_node<std::pair<boost::system::error_category const* const,std::default_delete<boost::system::detail::std_category> > > >(std::_Rb_tree_node<std::pair<boost::system::error_category const* const,std::default_delete<boost::system::detail::std_category> > > >*,std::default_delete<boost::system::detail::std_category> > >&&))

ld: error: undefined symbol: std::terminate()
>>> referenced by x.cpp
>>>               /tmp/x-dd4c59.o:(__clang_call_terminate)

ld: error: undefined symbol: std::__cxx11::basic_string<char,std::allocator<char> >::empty() const
>>> referenced by x.cpp
>>>               /tmp/x-dd4c59.o:(boost::system::system_error::what() const)
>>> referenced by x.cpp
>>>               /tmp/x-dd4c59.o:(boost::system::system_error::what() const)

ld: error: undefined symbol: std::runtime_error::what() const
>>> referenced by x.cpp
>>>               /tmp/x-dd4c59.o:(boost::system::system_error::what() const)
>>> referenced by x.cpp
>>>               /tmp/x-dd4c59.o:(boost::system::system_error::what() const)

ld: error: undefined symbol: std::__cxx11::basic_string<char,std::allocator<char> >::operator=(char const*)
>>> referenced by x.cpp
>>>               /tmp/x-dd4c59.o:(boost::system::system_error::what() const)

ld: error: undefined symbol: std::__cxx11::basic_string<char,std::allocator<char> >::operator+=(char const*)
>>> referenced by x.cpp
>>>               /tmp/x-dd4c59.o:(boost::system::system_error::what() const)

ld: error: undefined symbol: std::__cxx11::basic_string<char,std::allocator<char> >::operator+=(std::__cxx11::basic_string<char,std::allocator<char> > const&)
>>> referenced by x.cpp
>>>               /tmp/x-dd4c59.o:(boost::system::system_error::what() const)

ld: error: undefined symbol: std::__cxx11::basic_string<char,std::allocator<char> >::~basic_string()
>>> referenced by x.cpp
>>>               /tmp/x-dd4c59.o:(boost::system::system_error::what() const)
>>> referenced by x.cpp
>>>               /tmp/x-dd4c59.o:(boost::system::system_error::what() const)
>>> referenced by x.cpp
>>>               /tmp/x-dd4c59.o:(boost::system::error_category::message(int,unsigned long) const)
>>> referenced by x.cpp
>>>               /tmp/x-dd4c59.o:(boost::system::system_error::~system_error())

ld: error: undefined symbol: __cxa_end_catch
>>> referenced by x.cpp
>>>               /tmp/x-dd4c59.o:(boost::system::system_error::what() const)
>>> referenced by x.cpp
>>>               /tmp/x-dd4c59.o:(boost::system::error_category::message(int,std::default_delete<boost::system::detail::std_category> > >&&))

ld: error: undefined symbol: std::__cxx11::basic_string<char,std::allocator<char> >::c_str() const
>>> referenced by x.cpp
>>>               /tmp/x-dd4c59.o:(boost::system::system_error::what() const)
>>> referenced by x.cpp
>>>               /tmp/x-dd4c59.o:(boost::system::error_category::message(int,unsigned long) const)

ld: error: undefined symbol: std::_V2::error_category::~error_category()
>>> referenced by x.cpp
>>>               /tmp/x-dd4c59.o:(boost::system::detail::std_category::~std_category())

ld: error: undefined symbol: operator delete(void*)
>>> referenced by x.cpp
>>>               /tmp/x-dd4c59.o:(boost::system::detail::std_category::~std_category())
>>> referenced by x.cpp
>>>               /tmp/x-dd4c59.o:(boost::system::system_error::~system_error())
>>> referenced by x.cpp
>>>               /tmp/x-dd4c59.o:(boost::system::detail::to_std_category(boost::system::error_category const&))
>>> referenced by x.cpp
>>>               /tmp/x-dd4c59.o:(__gnu_cxx::new_allocator<std::_Rb_tree_node<std::pair<boost::system::error_category const* const,std::default_delete<boost::system::detail::std_category> > > > >::deallocate(std::_Rb_tree_node<std::pair<boost::system::error_category const* const,unsigned long))
>>> referenced by x.cpp
>>>               /tmp/x-dd4c59.o:(boost::exception_detail::error_info_injector<boost::thread_resource_error>::~error_info_injector())
>>> referenced by x.cpp
>>>               /tmp/x-dd4c59.o:(boost::thread_resource_error::~thread_resource_error())
>>> referenced by x.cpp
>>>               /tmp/x-dd4c59.o:(boost::thread_exception::~thread_exception())
>>> referenced by x.cpp
>>>               /tmp/x-dd4c59.o:(boost::exception_detail::clone_impl<boost::exception_detail::error_info_injector<boost::thread_resource_error> >::~clone_impl())
>>> referenced by x.cpp
>>>               /tmp/x-dd4c59.o:(boost::exception_detail::clone_impl<boost::exception_detail::error_info_injector<boost::thread_resource_error> >::clone() const)
>>> referenced by x.cpp
>>>               /tmp/x-dd4c59.o:(boost::wrapexcept<boost::thread_resource_error>::~wrapexcept())

ld: error: undefined symbol: std::runtime_error::~runtime_error()
>>> referenced by x.cpp
>>>               /tmp/x-dd4c59.o:(boost::system::system_error::~system_error())
>>> referenced by x.cpp
>>>               /tmp/x-dd4c59.o:(boost::system::system_error::system_error(boost::system::system_error const&))

ld: error: undefined symbol: __cxa_guard_acquire
>>> referenced by x.cpp
>>>               /tmp/x-dd4c59.o:(boost::system::detail::to_std_category(boost::system::error_category const&))
>>> referenced by x.cpp
>>>               /tmp/x-dd4c59.o:(boost::system::detail::to_std_category(boost::system::error_category const&))
>>> referenced by x.cpp
>>>               /tmp/x-dd4c59.o:(boost::system::detail::to_std_category(boost::system::error_category const&))

ld: error: too many errors emitted,stopping Now (use -error-limit=0 to see all errors)
clang: error: linker command Failed with exit code 1 (use -v to see invocation)

解决方法

首先,与库链接时顺序很重要。始终将库放在最后在命令行上。

其次,boost_thread 依赖于 boost_system 库(应该列在 before boost_thread)。

第三,clang 前端程序用于链接 C 程序,而不是 C++。对于 C++ 使用 clang++

要在受支持的系统上使用 POSIX 线程功能,还需要在构建时使用 -pthread 标志。

所以把它们放在一起:

$ clang++ -pthread x.cpp -lboost_system -lboost_thread