Catch2 如何在禁用异常的编译环境下使用?

Catch2 如何在禁用异常的编译环境下使用? Catch2 如何在禁用异常的编译环境下使用【免费下载链接】Catch2A modern, C-native, test framework for unit-tests, TDD and BDD - using C14, C17 and later (C11 support is in v2.x branch, and C03 on the Catch1.x branch)项目地址: https://gitcode.com/GitHub_Trending/ca/Catch2如果你的目标平台嵌入式系统、部分 RTOS 工具链等关闭了 C 异常而 Catch2 默认用异常向测试框架报错、并在REQUIRE系列断言失败时中止测试那么直接编译就会出问题。Catch2 提供了一套编译期配置来支持这种场景文档将其标注为实验性支持自 Catch2 2.4.0 引入核心做法是给测试目标加上无异常编译选项必要时再显式定义CATCH_CONFIG_DISABLE_EXCEPTIONS或自定义异常处理函数。先明确禁用异常后的两个行为变化来自 configuration.md 的 “Disabling exceptions” 一节原本以异常形式报告的错误其消息会写到Catch::cerr随后调用std::terminateREQUIRE系列宏的断言失败时当前 reporter 返回之后会调用std::terminate。也就是说CHECK系列断言照常运行并汇报但任何“需要抛异常”的路径都会直接终止进程。先弄清哪些宏控制行为docs/configuration.md 给出了三个相关宏宏作用CATCH_CONFIG_DISABLE_EXCEPTIONS强制以无异常模式编译。Catch2 也能自动检测编译器是否禁用了异常此宏用于强制CATCH_CONFIG_DISABLE_EXCEPTIONS_CUSTOM_HANDLER启用自定义处理点由用户提供Catch::throw_exception的定义替代默认的“写Catch::cerr后std::terminate”CATCH_CONFIG_NO_DISABLE_EXCEPTIONS反向开关取消自动检测出的无异常模式自动检测逻辑见 catch_compiler_capabilities.hpp 第 375–379 行当内部检测标记、CATCH_CONFIG_DISABLE_EXCEPTIONS与CATCH_CONFIG_NO_DISABLE_EXCEPTIONS都未定义时Catch2 自行定义CATCH_CONFIG_DISABLE_EXCEPTIONS。所以只要整个构建确实禁用了异常通常不写宏也能工作显式定义只是消除歧义。无异常模式下 Catch2 的try/catch宏会被展开为空壳见 catch_compiler_capabilities.hpp 第 456–464 行#if defined(CATCH_CONFIG_DISABLE_EXCEPTIONS) #define CATCH_TRY if ((true)) #define CATCH_CATCH_ALL if ((false)) #define CATCH_CATCH_ANON(type) if ((false)) #else #define CATCH_TRY try #define CATCH_CATCH_ALL catch (...) #define CATCH_CATCH_ANON(type) catch (type) #endif默认的“替代表抛异常”处理在 catch_enforce.cpp 第 15–22 行#if defined(CATCH_CONFIG_DISABLE_EXCEPTIONS) !defined(CATCH_CONFIG_DISABLE_EXCEPTIONS_CUSTOM_HANDLER) [[noreturn]] void throw_exception(std::exception const e) { Catch::cerr() Catch will terminate because it needed to throw an exception.\n The message was: e.what() \n; std::terminate(); } #endif注意该定义只在“无异常且未定义CATCH_CONFIG_DISABLE_EXCEPTIONS_CUSTOM_HANDLER”时存在——一旦你启用了自定义处理点就必须自己提供这个函数。配置无异常编译仓库自带的 tests/ExtraTests/CMakeLists.txt 第 91–102 行是官方测试目标的做法可以直接照搬其编译选项add_executable(DisabledExceptions-DefaultHandler ${TESTS_DIR}/X03-DisabledExceptions-DefaultHandler.cpp) add_executable(DisabledExceptions-CustomHandler ${TESTS_DIR}/X04-DisabledExceptions-CustomHandler.cpp) foreach(target DisabledExceptions-DefaultHandler DisabledExceptions-CustomHandler) target_compile_options(${target} PUBLIC $$CXX_COMPILER_ID:MSVC:/EHs-c-;/D_HAS_EXCEPTIONS0 $$OR:$CXX_COMPILER_ID:Clang,$CXX_COMPILER_ID:GNU,$CXX_COMPILER_ID:QCC,$CXX_COMPILER_ID:AppleClang:-fno-exceptions ) target_link_libraries(${target} Catch2_buildall_interface) endforeach() target_compile_definitions(DisabledExceptions-CustomHandler PUBLIC CATCH_CONFIG_DISABLE_EXCEPTIONS_CUSTOM_HANDLER)移植到自己的项目时要点是编译器开关分两类MSVC 用/EHs-c-并定义_HAS_EXCEPTIONS0Clang / GCC / QCC / AppleClang 用-fno-exceptions。上面用的是 CMake 生成器表达式按编译器 ID 选择等价的手写形式是 GCC/Clang 下加-fno-exceptionsMSVC 下加/EHs-c- /D_HAS_EXCEPTIONS0。PUBLIC不能少这里的选项是PUBLIC的目的就是把无异常标志传递到 Catch2 库本身。官方链接的是Catch2_buildall_interface即从源码构建 Catch2 的接口目标。如果你链接的是已经用默认选项构建好的预编译 Catch2 库库内部仍是异常开启状态与你目标的无异常模式不一致——正确做法是像官方测试一样把无异常选项传导到 Catch2 的编译中以源码方式集成 Catch2或自行用同样选项重编。宏只加在需要的目标上CATCH_CONFIG_DISABLE_EXCEPTIONS_CUSTOM_HANDLER只定义在启用自定义处理的目标上见上方target_compile_definitions行默认处理目标不定义任何额外宏。自定义处理点开启后你需要提供一个定义官方测试 X04-DisabledExceptions-CustomHandler.cpp 第 13–22 行给出的实现是namespace Catch { [[noreturn]] void throw_exception(std::exception const e) { std::cerr CUSTOM HANDLER run terminates because an exception was thrown.\n The message was: e.what() \n; // Avoid abort and other exceptional exits -- there is no way // to tell CMake that abort is the desired outcome of a test. exit(1); } }函数签名与 docs/configuration.md 的要求一致[[noreturn]] void Catch::throw_exception(std::exception const)。你自己的实现可以记录日志、上报或按平台要求退出但必须最终终止控制流。用官方测试验证行为仓库里有一对现成的验证样本X03-DisabledExceptions-DefaultHandler.cpp默认处理和 X04-DisabledExceptions-CustomHandler.cpp自定义处理。X03 中有两个测试用例Tests that run4 条CHECK断言其中 2 条失败但测试应完整跑完并汇报Tests that abort第三条REQUIRE失败预期触发终止。tests/ExtraTests/CMakeLists.txt 为这两个目标登记了验收正则也就是判断运行结果是否正确的依据运行命令期望PASS_REGULAR_EXPRESSION不应出现FAIL_REGULAR_EXPRESSIONDisabledExceptions-DefaultHandler Tests that runassertions: 4 \| 2 passed \| 2 failedabort;terminate;fatalDisabledExceptions-DefaultHandler Tests that abort仅非 Windows 登记Catch will terminate无DisabledExceptions-CustomHandler Tests that runassertions: 4 \| 2 passed \| 2 failed CUSTOM HANDLER DisabledExceptions-CustomHandler Tests that abort CUSTOM HANDLER 无按此验证先按上一节编译出两个可执行文件再分别运行上面四个命令。默认处理跑Tests that run时应看到断言汇总assertions: 4 | 2 passed | 2 failed且没有 abort/terminate 字样——这说明无异常模式下普通的失败断言仍能正常汇报跑Tests that abort时应看到 catch_enforce.cpp 中那条Catch will terminate because it needed to throw an exception.对应REQUIRE失败后的终止行为。自定义处理则相反Tests that run中不应出现CUSTOM HANDLER输出CHECK失败不需要抛异常只有Tests that abort才打印 CUSTOM HANDLER 并以exit(1)退出。一个值得注意的细节X03 的Tests that abort用例里先用std::set_terminate把终止行为改成exit(1)见 X03 第 27 行原因是 CMake 无法声明“abort 就是期望结果”而默认处理引发的终止在 Windows 上会触发即时调试器弹窗所以官方只在该用例上加了if(NOT WIN32)的登记CMakeLists.txt 第 149–155 行。如果你在 Windows 上做同样的手动验证进程终止的表现形式可能不同这属于文档已说明的平台差异。限制与边界文档原文称这是experimental support“We also provide an experimental support for disabling exceptions”即行为不承诺向后兼容使用时留意所锁定的 Catch2 版本。两类终止行为是固定语义不是可配置的内部错误 → 消息写入Catch::cerr后std::terminateREQUIRE失败 → reporter 返回后std::terminate。自定义处理点只能替换“替代表抛异常”的这一个入口改变不了REQUIRE失败后终止的事实。CATCH_CONFIG_DISABLE_EXCEPTIONS等配置宏属于编译期配置和文档中其他CATCH_CONFIG_*宏一样应通过编译定义统一给到参与链接的所有翻译单元不要只加在个别文件上。文档没有给出性能数据或其他平台的专项说明本文只覆盖“无异常编译 默认/自定义处理 运行验证”这一条路径。更多编译期开关前缀宏、CATCH_CONFIG_DISABLE等见 configuration.md。【免费下载链接】Catch2A modern, C-native, test framework for unit-tests, TDD and BDD - using C14, C17 and later (C11 support is in v2.x branch, and C03 on the Catch1.x branch)项目地址: https://gitcode.com/GitHub_Trending/ca/Catch2创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考