主项目用C++11时,如何为单元测试指定不同CMAKE_CXX_STANDARD?
解决CMake子目录无法覆盖全局C++标准的问题
这个需求完全可行,问题出在CMake的属性传递逻辑——顶层设置的CMAKE_CXX_STANDARD会作为默认值传递给子目录的所有目标,直接在tests目录下设置这个变量不会覆盖已创建目标的标准配置,因为目录级变量不会自动更新已存在的目标属性。下面是具体解决方案:
方案1:针对测试目标单独指定C++标准
不要在tests/CMakeLists.txt中直接设置CMAKE_CXX_STANDARD,而是在创建测试可执行文件后,通过目标属性强制指定C++17:
方式A:用set_target_properties
# 假设你的集成测试目标名为integration_tests add_executable(integration_tests src/integration_tests.cpp) # 给该目标单独设置C++17标准 set_target_properties(integration_tests PROPERTIES CXX_STANDARD 17 CXX_STANDARD_REQUIRED ON # 强制要求编译器支持C++17,否则报错 CXX_EXTENSIONS OFF # 禁用编译器扩展,使用纯标准C++17 )
方式B:用target_compile_features
如果想更精准地指定语言特性,也可以直接关联C++17的标准特性集:
target_compile_features(integration_tests PRIVATE cxx_std_17)
这两种方式都只会让测试目标使用C17,不会影响项目主体的C11配置。
方案2:处理std::filesystem的链接兼容性
部分旧版本编译器(比如GCC 8.x及更早、Clang 8.x及更早)中,std::filesystem需要单独链接对应的标准库组件,可在测试目标中添加条件判断:
if(CMAKE_CXX_COMPILER_ID STREQUAL "GNU" AND CMAKE_CXX_VERSION VERSION_LESS 9.0) target_link_libraries(integration_tests PRIVATE stdc++fs) elseif(CMAKE_CXX_COMPILER_ID STREQUAL "Clang" AND CMAKE_CXX_VERSION VERSION_LESS 9.0) target_link_libraries(integration_tests PRIVATE c++fs) endif()
目前主流CI服务器的编译器版本都已支持无需额外链接的C++17 filesystem,这个判断主要是兼容旧环境。
为什么子目录设置CMAKE_CXX_STANDARD无效?
CMAKE_CXX_STANDARD是目录级变量,顶层设置后会被所有子目录继承。如果子目录中的目标是在设置该变量之前创建的,或者目标继承了上层目录的默认配置,那么子目录新设置的变量值不会自动覆盖已存在目标的属性。因此必须针对单个目标单独修改属性,而非修改目录变量。
内容的提问来源于stack exchange,提问作者konse
相关产品推荐
相关产品推荐

