链接Homebrew libc++时Boost异常无法捕获的问题排查
问题描述
环境信息
- macOS 13
- clang++:Homebrew clang 15.0.6
- boost:Homebrew boost 1.81.0
测试代码(test.cpp)
#include <boost/program_options.hpp> #include <iostream> int main(int argc, char** argv){ namespace bpo = boost::program_options; bpo::options_description options("Allowed options"); options.add_options(); bpo::variables_map options_vm; try { bpo::store(bpo::parse_command_line(argc, argv, options), options_vm); bpo::notify(options_vm); } catch(boost::program_options::error &e){ std::cerr << e.what() << std::endl; exit(0); } }
正常编译运行情况
使用以下命令编译:
clang++ -isystem /usr/local/include -L/usr/local/lib -lboost_program_options test.cpp
编译后运行 ./a.out --asdf,程序能正确捕获异常并打印错误后退出。
异常情况(链接Homebrew libc++)
由于系统自带libc不支持-D_LIBCPP_ENABLE_ASSERTIONS=1编译选项,尝试链接Homebrew版本的libc,编译命令:
clang++ -isystem /usr/local/include -L/usr/local/opt/llvm/lib/c++ -lc++ -Wl,-rpath,/usr/local/opt/llvm/lib/c++ -L/usr/local/lib -lboost_program_options test.cpp
此时运行 ./a.out --asdf,程序崩溃并输出:
libc++abi: terminating with uncaught exception of type boost::wrapexcept<boost::program_options::unknown_option>
疑问
是否因为Homebrew的boost库是链接系统原生libc编译的,而不是Homebrew LLVM的libc?该如何解决这个问题?
补充尝试
使用--sysroot指定Homebrew LLVM路径编译:
clang++ --sysroot=/usr/local/opt/llvm -I/usr/local/include -L/usr/local/lib -lboost_program_options test.cpp
编译时报错:
In file included from test.cpp:2: In file included from /usr/local/include/boost/program_options.hpp:15: In file included from /usr/local/include/boost/program_options/options_description.hpp:11: In file included from /usr/local/include/boost/program_options/config.hpp:10: In file included from /usr/local/include/boost/config.hpp:57: In file included from /usr/local/include/boost/config/platform/macos.hpp:28: /usr/local/include/boost/config/detail/posix_features.hpp:18:15: fatal error: 'unistd.h' file not found # include <unistd.h> ^~~~~~~~~~ 1 error generated.
原因分析与解决方案
原因
你的猜测完全正确:Homebrew官方预编译的boost库是基于系统原生libc编译的。当你用Homebrew的clang链接自家libc时,程序中同时存在两个不同版本的libc实现,导致**C标准库的ABI不兼容**——boost抛出的异常由系统libc的异常机制生成,但你的程序用Homebrew libc的逻辑去捕获,两者不匹配,catch块无法识别该异常,最终触发崩溃。
另外,--sysroot=/usr/local/opt/llvm的用法错误,Homebrew的llvm包不包含完整的macOS系统SDK头文件,所以会找不到unistd.h这类系统头文件。
解决方法
有两种可行方案:
方案1:使用Homebrew的boost-libcxx包(推荐)
Homebrew提供了专门针对libc++编译的boost分支包,直接安装即可:
brew install boost-libcxx
编译程序时指定使用该版本的boost:
clang++ -isystem /usr/local/opt/boost-libcxx/include -L/usr/local/opt/boost-libcxx/lib -lboost_program_options -stdlib=libc++ -L/usr/local/opt/llvm/lib/c++ -Wl,-rpath,/usr/local/opt/llvm/lib/c++ test.cpp
方案2:从源码编译boost,指定链接Homebrew libc++
如果需要自定义编译参数,可手动编译boost:
- 获取boost 1.81.0源码:可以用
brew fetch --force --deps boost获取Homebrew的源码包,解压后进入源码目录 - 在源码目录创建
user-config.jam,添加以下内容:using clang : 15.0.6 : "/usr/local/opt/llvm/bin/clang++" : <cxxflags>"-stdlib=libc++ -isystem/usr/local/opt/llvm/include/c++/v1" <linkflags>"-L/usr/local/opt/llvm/lib/c++ -Wl,-rpath,/usr/local/opt/llvm/lib/c++" ; - 编译b2工具:
./bootstrap.sh --with-toolset=clang - 编译并安装boost(指定路径避免覆盖原版本):
./b2 toolset=clang cxxflags="-stdlib=libc++" linkflags="-stdlib=libc++" install --prefix=/usr/local/boost-libcxx - 编译程序时使用自编译的boost:
clang++ -isystem /usr/local/boost-libcxx/include -L/usr/local/boost-libcxx/lib -lboost_program_options -stdlib=libc++ -L/usr/local/opt/llvm/lib/c++ -Wl,-rpath,/usr/local/opt/llvm/lib/c++ test.cpp
内容的提问来源于stack exchange,提问作者Bubaya
相关产品推荐
相关产品推荐

