M1 Mac下CMake构建C++程序无法捕获异常问题求助
问题解决:M1 MacBook上CMake构建C++23程序无法捕获异常
问题重现
在M1 MacBook上使用Clang 17/Apple Clang + CMake 3.28构建C++23程序时,程序无法捕获std::runtime_error,触发trace trap崩溃;但直接用clang++ -std=c++23 except.cpp othertu.cpp编译可正常捕获异常并输出内容。改用GCC构建则无问题。
测试代码如下:
CMakeLists.txt
cmake_minimum_required(VERSION 3.26) project(doesntwork VERSION 0.0.0.1) set(CMAKE_CXX_STANDARD 23) set(CMAKE_CXX_STANDARD_REQUIRED ON) set(CMAKE_CXX_EXTENSIONS OFF) add_executable(test except.cpp othertu.cpp)
except.cpp(主函数)
#include <print> #include <iostream> #include <stdexcept> #include "otherheader.h" int main() { try { int x = 0; std::cin >> x; magic ma(x); } catch (std::runtime_error const& e) { std::println("{}", e.what()); } }
otherheader.h
#include <print> void maythrow(); class magic{ public: magic(int x); };
othertu.cpp
#include "otherheader.h" void maythrow() { // 不存在test.txt文件,因此该函数总会抛出异常 // 这么写是为了避免编译器优化掉相关代码 std::ifstream file{"test.txt", std::ios::binary}; if (file) { std::println("good"); } else { throw std::runtime_error{"bad"}; } } magic::magic(int x) { if (x > 1) { maythrow(); } }
原因分析
CMake在Apple Silicon平台的默认编译配置中,Release模式下会默认启用-fno-exceptions选项,直接禁用了C++异常处理机制;而直接使用clang++编译时,默认会启用-fexceptions(异常支持),因此可以正常捕获异常。此外,othertu.cpp中缺失<fstream>和<stdexcept>头文件,虽然直接编译可能因间接包含侥幸通过,但属于未定义行为,可能加剧CMake构建时的异常问题。
解决方案
方案1:显式启用异常支持
在CMakeLists.txt中添加编译选项,强制开启异常支持:
cmake_minimum_required(VERSION 3.26) project(doesntwork VERSION 0.0.0.1) set(CMAKE_CXX_STANDARD 23) set(CMAKE_CXX_STANDARD_REQUIRED ON) set(CMAKE_CXX_EXTENSIONS OFF) # 显式开启C++异常支持 set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fexceptions") # 针对Release模式单独设置(如果需要保留Release优化) set(CMAKE_CXX_FLAGS_RELEASE "${CMAKE_CXX_FLAGS_RELEASE} -fexceptions") add_executable(test except.cpp othertu.cpp)
方案2:强制使用Debug模式构建
Debug模式下CMake默认不会禁用异常,你可以在构建时指定:
cmake .. -DCMAKE_BUILD_TYPE=Debug make
或者在CMakeLists.txt开头直接设置:
set(CMAKE_BUILD_TYPE Debug)
方案3:修复头文件缺失问题
在othertu.cpp中补充缺失的头文件,避免未定义行为:
#include "otherheader.h" #include <fstream> // 用于std::ifstream #include <stdexcept> // 用于std::runtime_error
验证步骤
- 修改上述文件后,删除原构建目录(
rm -rf build) - 重新执行构建命令:
mkdir build && cd build cmake .. make - 运行程序并输入大于1的整数,此时应正常捕获异常并输出
bad。
内容的提问来源于stack exchange,提问作者suspiciously_large_carrot
相关产品推荐
相关产品推荐

