如何通过CMake为多模块项目生成单份cppcheck/clang-tidy报告?
多模块CMake项目集成静态分析工具生成合并报告的解决方法
针对Cppcheck的解决思路
问题根源在于你当前的配置让每个模块运行cppcheck时都输出到同一个xml文件,后续模块的检查结果会直接覆盖前面的。有两种可行方案:
方案1:分模块生成报告后合并
- 修改CMake配置,让每个模块生成独立的xml报告,用模块名区分文件:
find_program(CMAKE_CXX_CPPCHECK NAMES cppcheck) if (CMAKE_CXX_CPPCHECK) list(APPEND CMAKE_CXX_CPPCHECK "--enable=warning" "--inconclusive" "--force" "--inline-suppr" "--suppressions-list=${CMAKE_SOURCE_DIR}/CppCheckSuppressions.txt" "--xml" "--output-file=${CMAKE_BINARY_DIR}/cppcheck-${PROJECT_NAME}.xml" ) endif()
这里用${PROJECT_NAME}(每个子模块的项目名)作为报告文件名的一部分,确保每个模块的报告不冲突。
- 添加CMake自定义目标,用cppcheck自带的
cppcheck-merge工具合并所有模块的报告:
find_program(CPPCHECK_MERGE NAMES cppcheck-merge) if (CPPCHECK_MERGE) # 收集所有模块生成的cppcheck xml文件 file(GLOB_RECURSE CPPCHECK_XML_FILES "${CMAKE_BINARY_DIR}/cppcheck-*.xml") # 创建合并报告的目标 add_custom_target(cppcheck-merge ALL COMMAND ${CPPCHECK_MERGE} ${CPPCHECK_XML_FILES} --output=${CMAKE_SOURCE_DIR}/cppcheck-results.xml DEPENDS ${CPPCHECK_XML_FILES} COMMENT "合并所有模块的cppcheck报告" ) endif()
构建项目时,cppcheck-merge目标会自动执行,把所有模块的报告合并成一份最终的cppcheck-results.xml。如果不想自动执行,去掉ALL关键字,手动运行make cppcheck-merge或ninja cppcheck-merge即可。
方案2:直接扫描整个源码树生成单份报告
跳过按模块逐个检查的方式,直接通过CMake自定义命令对整个项目的源码运行一次cppcheck:
find_program(CPPCHECK NAMES cppcheck) if (CPPCHECK) add_custom_target(cppcheck-all COMMAND ${CPPCHECK} --enable=warning --inconclusive --force --inline-suppr --suppressions-list=${CMAKE_SOURCE_DIR}/CppCheckSuppressions.txt --xml --output-file=${CMAKE_SOURCE_DIR}/cppcheck-results.xml ${CMAKE_SOURCE_DIR}/src # 替换成你的源码根目录,多个目录用空格分隔 COMMENT "对所有源码文件执行cppcheck静态分析" ) endif()
运行make cppcheck-all就能直接生成覆盖所有模块的单份报告,无需合并步骤。
针对Clang-Tidy的解决思路
Clang-Tidy遇到的问题和cppcheck一致,同样可以用分模块生成再合并,或者直接全量扫描的方式解决:
方案1:分模块生成后合并
- 配置每个模块生成独立的fix文件:
find_program(CMAKE_CXX_CLANG_TIDY NAMES clang-tidy) if (CMAKE_CXX_CLANG_TIDY) set(CMAKE_CXX_CLANG_TIDY ${CMAKE_CXX_CLANG_TIDY} --export-fixes=${CMAKE_BINARY_DIR}/clang-tidy-${PROJECT_NAME}.yaml --config-file=${CMAKE_SOURCE_DIR}/.clang-tidy # 你的clang-tidy配置文件路径 ) endif()
- 用脚本合并多个fix文件。由于Clang-Tidy没有官方合并工具,可以写一个简单的Python脚本(命名为
merge-clang-tidy.py):
import yaml import sys merged = {"Diagnostics": []} # 遍历所有输入的yaml文件 for file_path in sys.argv[1:-1]: try: with open(file_path, 'r') as f: data = yaml.safe_load(f) if data and "Diagnostics" in data: merged["Diagnostics"].extend(data["Diagnostics"]) except Exception as e: print(f"读取文件 {file_path} 失败: {e}", file=sys.stderr) # 写入合并后的结果 with open(sys.argv[-1], 'w') as f: yaml.dump(merged, f)
- 在CMake中添加自定义目标执行合并:
add_custom_target(clang-tidy-merge ALL COMMAND python3 ${CMAKE_SOURCE_DIR}/merge-clang-tidy.py ${CMAKE_BINARY_DIR}/clang-tidy-*.yaml ${CMAKE_SOURCE_DIR}/clang-tidy-results.yaml DEPENDS ${CMAKE_BINARY_DIR}/clang-tidy-*.yaml COMMENT "合并所有模块的clang-tidy报告" )
方案2:全量扫描生成单份报告
直接对所有源码文件运行Clang-Tidy:
find_program(CLANG_TIDY NAMES clang-tidy) if (CLANG_TIDY) # 收集所有C++源码文件 file(GLOB_RECURSE CPP_SOURCES "${CMAKE_SOURCE_DIR}/src/*.cpp" "${CMAKE_SOURCE_DIR}/src/*.h" # 可以添加更多需要扫描的文件类型或目录 ) add_custom_target(clang-tidy-all COMMAND ${CLANG_TIDY} ${CPP_SOURCES} --config-file=${CMAKE_SOURCE_DIR}/.clang-tidy --export-fixes=${CMAKE_SOURCE_DIR}/clang-tidy-results.yaml -- ${CMAKE_CXX_FLAGS} -I${CMAKE_SOURCE_DIR}/include # 添加项目的头文件搜索路径 # 其他编译选项按需添加 COMMENT "对所有源码文件执行clang-tidy静态分析" ) endif()
内容的提问来源于stack exchange,提问作者emes9
相关产品推荐
相关产品推荐

