Catch2 CMake 集成完全指南:从链接 Target、自动注册测试到分片与安装

📅 发布时间:2026/9/13 19:51:03
Catch2 CMake 集成完全指南:从链接 Target、自动注册测试到分片与安装
Catch2 CMake 集成完全指南从链接 Target、自动注册测试到分片与安装【免费下载链接】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/Catch2Catch2 本身就是用 CMake 构建的因此它为使用方提供了两条标准集成通道导出的namespacedCMake Target以及位于extras目录中用于把TEST_CASE自动注册进 CTest 的 CMake 脚本。本文基于 docs/cmake-integration.md 展开结合仓库中 CMakeLists.txt、src/CMakeLists.txt、extras/Catch.cmake 等源码实现系统讲解如何在自己的 CMake 工程中链接 Catch2、自动发现测试、按需分片以及通过 CMake 配置项、CATCH_CONFIG_*开关和多种安装方式接入 Catch2读完后可直接照搬到实际项目中。CMake TargetsCatch2::Catch2与Catch2::Catch2WithMainCatch2 的 CMake 构建会导出两个 targetCatch2::Catch2和Catch2::Catch2WithMain。Catch2::Catch2WithMain如果你的测试代码不需要自定义main函数应当使用它且只用它。链接它会自动添加正确的 include 路径并把你的目标与两个静态库链接到一起——一个实现 Catch2 本体一个实现其main入口。Catch2::Catch2如果你需要自定义main例如自己解析命令行参数、注入自定义 CLI 选项则只链接Catch2::Catch2。在系统已安装 Catch2 的前提下最小用法如下find_package(Catch2 3 REQUIRED) # 这些测试使用 Catch2 提供的 main add_executable(tests test.cpp) target_link_libraries(tests PRIVATE Catch2::Catch2WithMain) # 这些测试需要自己的 main add_executable(custom-main-tests test.cpp test-main.cpp) target_link_libraries(custom-main-tests PRIVATE Catch2::Catch2)以子目录方式使用add_subdirectory当 Catch2 以子目录形式被引入时这两个 target 同样可用。假设 Catch2 已克隆到lib/Catch2只需把上面的find_package调用替换为add_subdirectory(lib/Catch2)其余代码原样照搬即可。仓库 examples/CMakeLists.txt 中的示例正是这样做的它把所有示例目标与Catch2WithMain链接从而省去手写main。需要自定义main时可以参考 examples/232-Cfg-CustomMain.cpp它创建唯一的Catch::Session实例基于Catch::Clara在 Catch2 既有命令行解析器之上追加--height之类的自定义选项再交给session.applyCommandLine处理最后调用session.run()。使用 FetchContent 拉取如果你不希望把 Catch2 提交进自己的仓库可以使用 CMake 的 FetchContentInclude(FetchContent) FetchContent_Declare( Catch2 GIT_REPOSITORY https://gitcode.com/GitHub_Trending/ca/Catch2.git GIT_TAG v3.15.2 # 或更新的 release当前仓库版本为 3.15.2 ) FetchContent_MakeAvailable(Catch2) add_executable(tests test.cpp) target_link_libraries(tests PRIVATE Catch2::Catch2WithMain)Target 的底层导出实现这两个 target 的生成与导出逻辑位于 src/CMakeLists.txtCatch2库由 src/catch2 下的全部实现文件IMPL_SOURCES、INTERFACE_SOURCES、REPORTER_SOURCES、MATCHER_SOURCES、GENERATOR_SOURCES、BENCHMARK_SOURCES编译而成并通过add_library(Catch2::Catch2 ALIAS Catch2)提供命名空间别名它要求 C14target_compile_features(Catch2 PUBLIC cxx_std_14)并通过$BUILD_INTERFACE:.../$INSTALL_INTERFACE:...区分构建期与安装期的 include 路径Catch2WithMain单独编译 src/catch2/internal/catch_main.cpp输出名被设为Catch2Main并target_link_libraries(Catch2WithMain PUBLIC Catch2)这正是“链接 WithMain 即自动带上实现库”的原因安装时两者被打包进Catch2Targets导出集合并冠以Catch2::命名空间安装到${CMAKE_INSTALL_LIBDIR}/cmake/Catch2。安装后供find_package使用的配置文件是 CMake/Catch2Config.cmake.in它先检查Catch2::Catch2目标是否已存在以避免重复引入然后向CMAKE_MODULE_PATH追加自身所在目录这样include(Catch)等脚本也能被找到最后include(Catch2Targets.cmake)。此外顶层 CMakeLists.txt 还会在安装时生成catch2.pc与catch2-with-main.pc模板见 CMake/catch2.pc.in 与 CMake/catch2-with-main.pc.in为使用 pkg-config 的项目提供同样的链接信息。自动测试注册把TEST_CASE变成 CTest 用例Catch2 仓库的extras目录提供了三套辅助脚本Catch.cmake及其依赖CatchAddTests.cmake——推荐方案ParseAndAddCatchTests.cmake已弃用CatchShardTests.cmake及其依赖CatchShardTestsImpl.cmake。如果 Catch2 已安装到系统执行find_package(Catch2 REQUIRED)之后即可直接include这些脚本否则需要手动把extras目录加入CMAKE_MODULE_PATH。catch_discover_tests运行期枚举测试Catch.cmake提供函数catch_discover_tests。它的原理是运行编译好的测试可执行文件传入--list-tests --reporter json --out 临时文件再把 JSON 输出解析为一个个独立的 CTest 测试。从 extras/CatchAddTests.cmake 的实现可以看到它要求输出 JSON 的version字段为1随后逐条读取测试名、可选的 tags并为每个测试生成add_test与set_tests_properties写入 CTest 脚本。由于发现过程发生在构建/测试阶段新增或删除测试无需重新运行 CMake 配置。基本用法cmake_minimum_required(VERSION 3.16) project(baz LANGUAGES CXX VERSION 0.0.1) find_package(Catch2 REQUIRED) add_executable(tests test.cpp) target_link_libraries(tests PRIVATE Catch2::Catch2) include(CTest) include(Catch) catch_discover_tests(tests)使用 FetchContent 时的注意点使用 FetchContent 时include(Catch)会失败除非显式把extras目录加入CMAKE_MODULE_PATH# ... FetchContent ... # list(APPEND CMAKE_MODULE_PATH ${catch2_SOURCE_DIR}/extras) include(CTest) include(Catch) catch_discover_tests(tests)完整参数列表catch_discover_tests(target [TEST_SPEC arg1...] [EXTRA_ARGS arg1...] [WORKING_DIRECTORY dir] [TEST_PREFIX prefix] [TEST_SUFFIX suffix] [PROPERTIES name1 value1...] [TEST_LIST var] [REPORTER reporter] [OUTPUT_DIR dir] [OUTPUT_PREFIX prefix] [OUTPUT_SUFFIX suffix] [DISCOVERY_MODE POST_BUILD|PRE_TEST] [SKIP_IS_FAILURE] [ADD_TAGS_AS_LABELS] [DL_PATHS path...] [DL_FRAMEWORK_PATHS path...] )其中DL_PATHS与DL_FRAMEWORK_PATHS在 extras/Catch.cmake 中还有进一步支持分别对应 Linux/macOS/Windows 的LD_LIBRARY_PATH/DYLD_LIBRARY_PATH/PATH与 macOS 的DYLD_FRAMEWORK_PATH要求 CMake ≥ 3.22。各参数含义TEST_SPEC arg1...指定要传给测试可执行文件的测试用例、通配用例、标签或标签表达式与--list-test-names-only一起使用实现只发现子集测试。EXTRA_ARGS arg1...运行每个测试时额外追加的命令行参数。WORKING_DIRECTORY dir运行已发现测试的目录缺省为当前二进制目录。TEST_PREFIX prefix为每个发现的测试名添加前缀。当同一个测试可执行文件被多次调用catch_discover_tests()且使用不同TEST_SPEC/EXTRA_ARGS时非常有用。TEST_SUFFIX suffix与TEST_PREFIX相对为测试名追加后缀两者可同时使用。PROPERTIES name1 value1...为本次调用发现的所有测试设置额外属性。TEST_LIST var把测试列表保存到变量var而非默认的target_TESTS便于同一可执行文件被多次发现时区分注意该变量只在 CTest 运行期可用。REPORTER reporter使用指定 reporter 运行测试最终以--reporter reporter传给测试程序。OUTPUT_DIR dir以--out dir/test_name形式传给可执行文件文件名与测试名一致。应优先用它而不是EXTRA_ARGS --out foo以避免并行执行时写同一输出文件的竞争条件。OUTPUT_PREFIX prefix与OUTPUT_DIR联用得到--out dir/prefixtest_name。OUTPUT_SUFFIX suffix与OUTPUT_DIR联用得到--out dir/test_namesuffix可用于补充扩展名如.xml。DISCOVERY_MODE mode控制测试发现时机。POST_BUILD默认在构建时发现PRE_TEST推迟到测试执行前适用于交叉编译等场景。未传参时取CMAKE_CATCH_DISCOVER_TESTS_DISCOVERY_MODE变量的值实现全局统一行为。注意在 Apple Silicon Xcode 生成器下必须使用PRE_TEST否则默认的POST_BUILD会因 macOS 拒绝运行未签名二进制而报Result: Subprocess killed——Xcode 只在 post-build 脚本之后才对测试可执行文件签名。SKIP_IS_FAILURE让被跳过的测试按失败处理。默认情况下extras/Catch.cmake 会给测试附加SKIP_RETURN_CODE 4Catch2 约定跳过返回码以实现 CTest 对跳过状态的识别。ADD_TAGS_AS_LABELS把测试的 tags 同时作为 CTest 标签labels添加。实现上extras/CatchAddTests.cmake 会解析 JSON 中的tags数组并对含分号的标签做\;转义后写入LABELS属性。DL_PATHS path.../DL_FRAMEWORK_PATHS path...设置测试执行时动态链接器查找共享库/DLL 的路径分别写入LD_LIBRARY_PATH/PATH与DYLD_FRAMEWORK_PATH在发现测试和真正执行测试时都会生效。仓库自带的使用实例位于 tests/TestScripts/DiscoverTests/CMakeLists.txt它以add_subdirectory引入 Catch2链接Catch2::Catch2WithMain并同时使用了ADD_TAGS_AS_LABELS、DISCOVERY_MODE PRE_TEST且在 CMake ≥ 3.27 时追加DL_PATHS。版本提示catch_discover_tests内部依赖 CMake 的 JSON 字符串解析能力extras/Catch.cmake 中明确要求 CMake 版本 ≥ 3.19否则会以FATAL_ERROR终止。虽然入门示例只写了cmake_minimum_required(VERSION 3.16)实际使用该函数时请确保 CMake 版本满足此要求。ParseAndAddCatchTests已弃用⚠ 该脚本在 Catch2 2.13.4 起被标记为弃用由上文catch_discover_tests方案取代。它的工作方式与运行期发现截然不同静态解析目标关联的所有实现文件再通过 CTest 的add_test注册测试。这种方案有固有缺陷被注释掉的测试也会被注册而且它只能识别断言宏的一个子集任何无法解析出宏的测试会被静默忽略。用法cmake_minimum_required(VERSION 3.16) project(baz LANGUAGES CXX VERSION 0.0.1) find_package(Catch2 REQUIRED) add_executable(tests test.cpp) target_link_libraries(tests PRIVATE Catch2::Catch2) include(CTest) include(ParseAndAddCatchTests) ParseAndAddCatchTests(tests)自定义点均为变量默认值见下表变量作用默认值PARSE_CATCH_TESTS_VERBOSEON时打印调试信息OFFPARSE_CATCH_TESTS_NO_HIDDEN_TESTSON时不注册隐藏测试带[.]或[.foo]标签OFFPARSE_CATCH_TESTS_ADD_FIXTURE_IN_TEST_NAMEON时把 fixture 类名加入 CTest 测试名ONPARSE_CATCH_TESTS_ADD_TARGET_IN_TEST_NAMEON时把 target 名加入 CTest 测试名ONPARSE_CATCH_TESTS_ADD_TO_CONFIGURE_DEPENDSON时把测试文件加入CMAKE_CONFIGURE_DEPENDS测试文件变化会触发重新 configure 以自动发现新测试OFF还可在调用前设置OptionalCatchTestLauncher来包装启动命令例如让部分测试通过 MPI 运行set(OptionalCatchTestLauncher ${MPIEXEC} ${MPIEXEC_NUMPROC_FLAG} ${NUMPROC}) ParseAndAddCatchTests(mpi_foo) unset(OptionalCatchTestLauncher) ParseAndAddCatchTests(bar)catch_add_sharded_tests把测试拆成随机分片CatchShardTests.cmake自 Catch2 3.1.0 引入。catch_add_sharded_tests(TEST_BINARY)把TEST_BINARY的测试拆分到多个分片shard中。每个分片内测试的内容与顺序是随机化的种子每次调用 CTest 都会变化——实现上extras/CatchShardTestsImpl.cmake 在生成的 CTest 脚本里先用string(RANDOM ...)生成 8 位十六进制种子再为每个分片注册add_test(target-shard-i/n binary --shard-index i --shard-count n --rng-seed 0xseed --order rand ...)从而让每次 CTest 运行的测试分布都不同。目前支持三个自定义点SHARD_COUNT分片数量。未指定时extras/CatchShardTests.cmake 中默认值为2。REPORTER测试使用的 reporter 规格。TEST_SPEC用于过滤测试的测试规格。示例include(CatchShardTests) catch_add_sharded_tests(foo-tests SHARD_COUNT 4 REPORTER xml::out- TEST_SPEC A ) catch_add_sharded_tests(tests SHARD_COUNT 8 REPORTER xml::out- TEST_SPEC B )上述配置共注册 12 个 CTest 测试4 8 个分片各自从对应测试二进制中按 test spec 过滤后运行。仓库中 tests/TestScripts/testSharding.py 与 tests/TestScripts/testBazelSharding.py 分别验证了分片前后测试集合的一致性以及 Bazel 环境下分片相关环境变量的行为。注意该脚本目前是“每次 CTest 运行重新播种分片”的概念验证实现因此不支持当前也不打算支持catch_discover_tests的全部自定义点。CMake 工程选项作为可被消费的 CMake 工程Catch2 提供了若干选项定义于顶层 CMakeLists.txt选项作用默认值BUILD_TESTINGON且不是作为子工程使用时构建 Catch2 测试二进制ONCATCH_INSTALL_DOCSON时把文档安装到系统ONCATCH_INSTALL_EXTRASON时把extras上述 CMake 脚本、调试器辅助文件一并安装ONCATCH_DEVELOPMENT_BUILDON时按“开发 Catch2 本身”配置构建启用测试工程、警告等OFFCATCH_ENABLE_REPRODUCIBLE_BUILDON时为构建添加可复现性编译参数ON开启CATCH_DEVELOPMENT_BUILD后还会解锁一组开发用选项CATCH_BUILD_TESTING构建 SelfTest 工程默认ON。注意 Catch2 同时遵守标准BUILD_TESTING变量两者都需为ON才会构建 SelfTest任意一个设为OFF都能禁用。CATCH_BUILD_EXAMPLES构建 examples 下的用法示例默认OFF。CATCH_BUILD_EXTRA_TESTS构建 tests/ExtraTests 额外测试默认OFF。CATCH_BUILD_FUZZERS构建 fuzzing 模糊测试入口默认OFF。CATCH_ENABLE_WERROR为编译添加-Werror或等价标志默认ON。CATCH_BUILD_SURROGATESON时逐个独立编译 Catch2 的每个头文件生成“代理翻译单元”以验证它们自给自足默认OFF。从源码结构看顶层 CMakeLists.txt 还通过cmake_dependent_option声明了CATCH_BUILD_BENCHMARKS构建 benchmarks、CATCH_ENABLE_COVERAGE生成覆盖率、CATCH_ENABLE_CONFIGURE_TESTS与CATCH_ENABLE_CMAKE_HELPER_TESTS均为“非常昂贵”的 CMake 自身测试默认OFF等更多选项开发 Catch2 时可按需开启。另外Catch2 不支持 in-tree 构建当CMAKE_BINARY_DIR与源码目录相同时会直接FATAL_ERROR请始终使用独立构建目录。在 CMake 中定制CATCH_CONFIG_*编译期选项CMake 对CATCH_CONFIG_*选项的支持自 Catch2 3.0.1 引入。由于 Catch2 v3 采用新的分离编译模型docs/configuration.md 中列出的所有编译期配置项都可以通过 CMake 设置把对应选项定义为ON即可例如-DCATCH_CONFIG_NOSTDOUTON。这些选项在 CMake/CatchConfigOptions.cmake 中成批生成分为两类可双向覆盖的选项同时生成CATCH_CONFIG_X与CATCH_CONFIG_NO_X包括ANDROID_LOGWRITE、BAZEL_SUPPORT、COLOUR_WIN32、COUNTER、CPP11_TO_STRING、CPP17_BYTE、CPP17_OPTIONAL、CPP17_STRING_VIEW、CPP17_UNCAUGHT_EXCEPTIONS、CPP17_VARIANT、GLOBAL_NEXTAFTER、POSIX_SIGNALS、USE_ASYNC、WCHAR、WINDOWS_SEH、GETENV、EXPERIMENTAL_STATIC_ANALYSIS_SUPPORT、USE_BUILTIN_CONSTANT_P、DEPRECATION_ANNOTATIONS、THREAD_SAFE_ASSERTIONS等单向选项包括DISABLE_EXCEPTIONS、DISABLE_EXCEPTIONS_CUSTOM_HANDLER、DISABLE、DISABLE_STRINGIFICATION、ENABLE_ALL_STRINGMAKERS、ENABLE_OPTIONAL_STRINGMAKER、ENABLE_PAIR_STRINGMAKER、ENABLE_TUPLE_STRINGMAKER、ENABLE_VARIANT_STRINGMAKER、EXPERIMENTAL_REDIRECT、FAST_COMPILE、NOSTDOUT、PREFIX_ALL、PREFIX_MESSAGES、WINDOWS_CRTDBG等。关键语义把选项设为OFF并不会“关闭”它。要强制禁用某个特性需要把对应的_NO_形式设为ON。以颜色支持为例官方给出的行为真值表如下-DCATCH_CONFIG_COLOUR_WIN32-DCATCH_CONFIG_NO_COLOUR_WIN32结果ONONerror配置错误ONOFFforce-on强制启用OFFONforce-off强制禁用OFFOFFauto-detect自动检测类似的配置如CATCH_CONFIG_CONSOLE_WIDTH默认80与CATCH_CONFIG_DEFAULT_REPORTER默认console也可作为 CMake cache 变量在 CMake/CatchConfigOptions.cmake 中看到。这些选项最终会在配置阶段写入由 src/catch2/catch_user_config.hpp.in 生成的catch_user_config.hpp随库一起编译。三种安装方式从 Git 仓库安装如果包管理器提供的 Catch2 版本过旧可以直接从仓库安装。拥有足够权限时$ git clone https://gitcode.com/GitHub_Trending/ca/Catch2.git $ cd Catch2 $ cmake -B build -S . -DBUILD_TESTINGOFF $ sudo cmake --build build/ --target install如果没有超级用户权限配置时还需指定CMAKE_INSTALL_PREFIX并让后续find_package(Catch2 ...)的查找路径与之对应。通过 vcpkg 安装也可以使用 vcpkg 依赖管理器构建安装 Catch2git clone vcpkg 官方仓库地址 cd vcpkg ./bootstrap-vcpkg.sh ./vcpkg integrate install ./vcpkg install catch2vcpkg 中的 catch2 port 由微软团队成员与社区贡献者维护若版本过期可在 vcpkg 仓库上提交 issue 或 pull request 更新。通过 Bazel 使用Catch2 是 Bazel Central Registry 的受支持模块本仓库 MODULE.bazel 即声明module(name catch2)并依赖bazel_skylib、rules_cc、rules_license。在MODULE.bazel中加入对最新支持版本catch2模块的依赖后即可在 C 测试规则中链接catch2_maincc_test( name example_test, srcs [example_test.cpp], deps [ :example, catch2//:catch2_main, ], )结语围绕 docs/cmake-integration.md 这份文档本文覆盖了 Catch2 与 CMake 集成的完整链路从Catch2::Catch2/Catch2::Catch2WithMain两种链接方式含find_package、add_subdirectory、FetchContent三种接入形态到以运行期 JSON 枚举为基础的catch_discover_tests自动注册含全部 13 个参数与POST_BUILD/PRE_TEST两种发现模式再到静态解析的弃用方案ParseAndAddCatchTests、随机分片的catch_add_sharded_tests以及工程选项、CATCH_CONFIG_*开关真值表和 Git/vcpkg/Bazel 三种安装路径。所有参数与默认值均可在 extras 脚本、CMake 目录与 CMakeLists.txt 源码中找到对应实现可作为项目接入与排障的一手依据。【免费下载链接】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),仅供参考