CppCheckAnalysis.cmake 9.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268
  1. # - Run cppcheck on C/C++ source files as a custom target
  2. #
  3. # Requires these CMake modules:
  4. # Findcppcheck
  5. if(NOT CPPCHECK_FOUND)
  6. find_package(CPPCHECK)
  7. # Reset its value if it is on the cache
  8. set(CPPCHECK_EXCLUDED_HEADERS "" CACHE INTERNAL "")
  9. set(CPPCHECK_PROJECT_OPTIONS "" CACHE INTERNAL "")
  10. endif()
  11. set(CPPCHECK_REPORT_DIR ${CMAKE_BINARY_DIR}/cppcheck-reports CACHE STRING
  12. "The directory where to put the cppcheck reports.")
  13. set(CPPCHECK_MODULE_DIRECTORY_STRUCTURE FALSE CACHE BOOL
  14. "Whether the directory was a module type of structure. \
  15. If the directory has this type of structure - separate \
  16. directories containing independent sets of sources - \
  17. an analyse-<module> target will be created for each \
  18. module")
  19. set(CPPCHECK_CHECK_CONFIG FALSE CACHE BOOL
  20. "Whether the config should be checked (--check-config cppcheck option: Check cppcheck configuration. The normal code analysis is disabled by this flag")
  21. if(CPPCHECK_EXECUTABLE)
  22. execute_process(COMMAND ${CPPCHECK_EXECUTABLE} --version
  23. OUTPUT_VARIABLE CPPCHECK_VERSION
  24. ERROR_QUIET
  25. OUTPUT_STRIP_TRAILING_WHITESPACE)
  26. string(REPLACE "Cppcheck " "" CPPCHECK_VERSION ${CPPCHECK_VERSION})
  27. string(REPLACE "\n" "" CPPCHECK_VERSION ${CPPCHECK_VERSION})
  28. message("cppcheck version: ${CPPCHECK_VERSION}")
  29. endif(CPPCHECK_EXECUTABLE)
  30. if(NOT TARGET cppcheck_analyse_all)
  31. add_custom_target(cppcheck_analyse_all)
  32. set_target_properties(cppcheck_analyse_all PROPERTIES EXCLUDE_FROM_ALL TRUE)
  33. endif()
  34. # ::
  35. #
  36. # add_cppcheck_project_option(<header> ...)
  37. #
  38. #
  39. # Adds additional options to run cppcheck with
  40. #
  41. function(add_cppcheck_project_option)
  42. set(CPPCHECK_PROJECT_OPTIONS "${CPPCHECK_PROJECT_OPTIONS};${ARGN}" CACHE INTERNAL "")
  43. endfunction()
  44. # ::
  45. #
  46. # add_cppcheck_header_exclusion(<header> ...)
  47. #
  48. #
  49. # Causes warnings about missing includes for an header or list of header
  50. # files to be removed. Useful to ignore auto-generated header files.
  51. #
  52. function(add_cppcheck_header_exclusion)
  53. set(CPPCHECK_EXCLUDED_HEADERS "${CPPCHECK_EXCLUDED_HEADERS};${ARGN}" CACHE INTERNAL "")
  54. endfunction()
  55. # ::
  56. #
  57. # target_add_cppcheck(<target>
  58. # [ALL]
  59. # [IGNORE_WARNINGS]
  60. # [IGNORE_STYLE]
  61. # [IGNORE_PERFORMANCE]
  62. # [IGNORE_PORTABILITY]
  63. # [IGNORE_INFORMATION]
  64. # [IGNORE_UNUSED_FUNC]
  65. # [IGNORE_MISSING_INCLUDE]
  66. # [WARNINGS]
  67. # [STYLE]
  68. # [PERFORMANCE]
  69. # [PORTABILITY]
  70. # [INFORMATION]
  71. # [UNUSED_FUNC]
  72. # [MISSING_INCLUDE]
  73. # [FORCE_CHECK]
  74. # [INCLUDES])
  75. #
  76. # Adds a CMake target that causes the sources and header files used to
  77. # build <target> to be static analysed with the cppcheck tool.
  78. #
  79. # The checks to be performed can be controlled by giving some options.
  80. # If <ALL> was given, all checks will be performed. It is possible to
  81. # exclude a check by passing IGNORE_<CHECK>.
  82. #
  83. # If <ALL> was not given, then only the checks specified will be
  84. # performed. If no check was specified, then the static analysis will
  85. # not produce any warning.
  86. #
  87. # <FORCE_CHECK> runs cppcheck with the `--force` option.
  88. #
  89. # <INCLUDES> allows to specify an additional list of directories to look
  90. # for header files. This may be required as CMake does not return the
  91. # include directories for a library, when it is being linked with an
  92. # executable.
  93. #
  94. function(target_add_cppcheck _target_name)
  95. if(NOT TARGET ${_target_name})
  96. message(FATAL_ERROR
  97. "[CppCheck] add_cppcheck given a target name that does not exist: '${_target_name}' !")
  98. endif()
  99. # Find out the module name
  100. if (CPPCHECK_MODULE_DIRECTORY_STRUCTURE)
  101. file(RELATIVE_PATH rel ${CMAKE_SOURCE_DIR} ${CMAKE_CURRENT_SOURCE_DIR})
  102. set(dirname ${rel})
  103. while(NOT ${dirname} STREQUAL "" )
  104. set(prev_dirname ${dirname})
  105. get_filename_component(dirname ${prev_dirname} DIRECTORY)
  106. endwhile()
  107. set(_module_name "${prev_dirname}")
  108. set(_module_cppcheck_tgt "analyse-${_module_name}")
  109. if(NOT TARGET ${_module_cppcheck_tgt})
  110. add_custom_target(${_module_cppcheck_tgt})
  111. set_target_properties(${_module_cppcheck_tgt} PROPERTIES EXCLUDE_FROM_ALL TRUE)
  112. endif()
  113. endif()
  114. set(_cppcheck_args)
  115. #list(APPEND _cppcheck_args "--xml")
  116. #list(APPEND _cppcheck_args "--xml-version=2")
  117. foreach(_cppcheck_opt ${CPPCHECK_PROJECT_OPTIONS})
  118. list(APPEND _cppcheck_args ${_cppcheck_opt})
  119. endforeach()
  120. set(options
  121. IGNORE_WARNINGS
  122. IGNORE_STYLE
  123. IGNORE_PERFORMANCE
  124. IGNORE_PORTABILITY
  125. IGNORE_INFORMATION
  126. IGNORE_UNUSED_FUNC
  127. IGNORE_MISSING_INCLUDE
  128. WARNINGS
  129. STYLE
  130. PERFORMANCE
  131. PORTABILITY
  132. INFORMATION
  133. UNUSED_FUNC
  134. MISSING_INCLUDE
  135. FORCE_CHECK)
  136. set(multi_value_keywords INCLUDES)
  137. cmake_parse_arguments(CPPCHECK "${options}" "" "${multi_value_keywords}" ${ARGN})
  138. if(CPPCHECK_ALL)
  139. if(NOT CPPCHECK_IGNORE_WARNINGS)
  140. list(APPEND _cppcheck_args ${CPPCHECK_WARNINGS_ARG})
  141. endif()
  142. if(NOT CPPCHECK_IGNORE_STYLE)
  143. list(APPEND _cppcheck_args ${CPPCHECK_STYLE_ARG})
  144. endif()
  145. if(NOT CPPCHECK_IGNORE_PERFORMANCE)
  146. list(APPEND _cppcheck_args ${CPPCHECK_PERFORMANCE_ARG})
  147. endif()
  148. if(NOT CPPCHECK_IGNORE_PORTABILITY)
  149. list(APPEND _cppcheck_args ${CPPCHECK_PORTABILITY_ARG})
  150. endif()
  151. if(NOT CPPCHECK_IGNORE_INFORMATION)
  152. list(APPEND _cppcheck_args ${CPPCHECK_INFORMATION_ARG})
  153. endif()
  154. if(NOT CPPCHECK_IGNORE_UNUSED_FUNC)
  155. list(APPEND _cppcheck_args ${CPPCHECK_UNUSEDFUNC_ARG})
  156. endif()
  157. if(NOT CPPCHECK_IGNORE_MISSING_INCLUDE)
  158. list(APPEND _cppcheck_args ${CPPCHECK_MISSINGINCLUDE_ARG})
  159. endif()
  160. else()
  161. if(CPPCHECK_WARNINGS)
  162. list(APPEND _cppcheck_args ${CPPCHECK_WARNINGS_ARG})
  163. endif()
  164. if(CPPCHECK_STYLE)
  165. list(APPEND _cppcheck_args ${CPPCHECK_STYLE_ARG})
  166. endif()
  167. if(CPPCHECK_PERFORMANCE)
  168. list(APPEND _cppcheck_args ${CPPCHECK_PERFORMANCE_ARG})
  169. endif()
  170. if(CPPCHECK_PORTABILITY)
  171. list(APPEND _cppcheck_args ${CPPCHECK_PORTABILITY_ARG})
  172. endif()
  173. if(CPPCHECK_INFORMATION)
  174. list(APPEND _cppcheck_args ${CPPCHECK_INFORMATION_ARG})
  175. endif()
  176. if(CPPCHECK_UNUSED_FUNC)
  177. list(APPEND _cppcheck_args ${CPPCHECK_UNUSEDFUNC_ARG})
  178. endif()
  179. if(CPPCHECK_MISSING_INCLUDE)
  180. list(APPEND _cppcheck_args ${CPPCHECK_MISSINGINCLUDE_ARG})
  181. endif()
  182. endif()
  183. list(APPEND _cppcheck_args ${CPPCHECK_LIBRARY_ARG})
  184. list(APPEND _cppcheck_args ${CPPCHECK_LIBRARY_STANDARD_ARG})
  185. list(APPEND _cppcheck_args ${CPPCHECK_LANGUAGE_ARG})
  186. list(APPEND _cppcheck_args "--relative-paths=${CMAKE_CURRENT_SOURCE_DIR}")
  187. if(CPPCHECK_FORCE_CHECK)
  188. list(APPEND _cppcheck_args "--force")
  189. endif()
  190. get_target_property(_cppcheck_includes "${_target_name}" INCLUDE_DIRECTORIES)
  191. get_target_property(_cppcheck_sources "${_target_name}" SOURCES)
  192. list(APPEND _cppcheck_includes ${CPPCHECK_INCLUDES})
  193. message(STATUS "[CppCheck] _cppcheck_includes:${_cppcheck_includes}")
  194. set(_files)
  195. foreach(_source ${_cppcheck_sources})
  196. get_source_file_property(_cppcheck_lang "${_source}" LANGUAGE)
  197. get_source_file_property(_cppcheck_loc "${_source}" LOCATION)
  198. if("${_cppcheck_lang}" MATCHES "^CXX$" OR "${_cppcheck_lang}" MATCHES "^C$")
  199. list(APPEND _files "${_cppcheck_loc}")
  200. message(STATUS "[CppCheck] append file: ${_cppcheck_lang}|${_cppcheck_loc}")
  201. endif()
  202. endforeach()
  203. if (CPPCHECK_MODULE_DIRECTORY_STRUCTURE)
  204. set(cppcheck_target ${_module_cppcheck_tgt}-${_target_name})
  205. set(cppcheck_report_file ${CPPCHECK_REPORT_DIR}/${_module_name}-${_target_name})
  206. else()
  207. set(cppcheck_target analyse-${_target_name})
  208. set(cppcheck_report_file ${CPPCHECK_REPORT_DIR}/${_target_name})
  209. endif()
  210. if(CPPCHECK_CHECK_CONFIG)
  211. set(_cppcheck_check_config "true")
  212. else()
  213. set(_cppcheck_check_config "false")
  214. endif()
  215. if(MSVC)
  216. set(COMMAND_SCRPIT ${CMAKE_SOURCE_DIR}/addin/cmake/scripts/cppcheck-wrapper/win.bat)
  217. else()
  218. set(COMMAND_SCRPIT ${CMAKE_SOURCE_DIR}/addin/cmake/scripts/cppcheck-wrapper/uos.sh)
  219. endif(MSVC)
  220. add_custom_target(
  221. ${cppcheck_target}
  222. COMMAND
  223. ${COMMAND_SCRPIT}
  224. ${CPPCHECK_EXECUTABLE}
  225. "${_cppcheck_includes}"
  226. ${CPPCHECK_QUIET_ARG}
  227. ${CPPCHECK_TEMPLATE_ARG}
  228. ${_cppcheck_args}
  229. ${_files}
  230. WORKING_DIRECTORY
  231. "${CMAKE_CURRENT_SOURCE_DIR}"
  232. COMMENT
  233. "[CppCheck] ${cppcheck_target}: Running cppcheck on target ${_target_name}..."
  234. VERBATIM
  235. )
  236. set_target_properties(${cppcheck_target} PROPERTIES FOLDER "CodeAnalysis")
  237. add_dependencies(cppcheck_analyse_all ${cppcheck_target})
  238. if (CPPCHECK_MODULE_DIRECTORY_STRUCTURE)
  239. add_dependencies(${_module_cppcheck_tgt} ${cppcheck_target})
  240. endif()
  241. endfunction()