blob: dd79962f5bb3e842fa66ea681d3e20c0a1810a63 [file] [log] [blame]
Soby Mathewb4c6df42022-11-09 11:13:29 +00001#
2# SPDX-License-Identifier: BSD-3-Clause
3# SPDX-FileCopyrightText: Copyright TF-RMM Contributors.
4#
5
6if(RMM_STATIC_ANALYSIS)
7 find_program(RMM_STATIC_ANALYSIS_CPPCHECK_PATH "cppcheck"
8 DOC "Path to Cppcheck.")
9endif()
10
11if(EXISTS "${RMM_STATIC_ANALYSIS}")
12 mark_as_advanced(FORCE RMM_STATIC_ANALYSIS_CPPCHECK_PATH)
13else()
14 mark_as_advanced(CLEAR RMM_STATIC_ANALYSIS_CPPCHECK_PATH)
15endif()
16
17arm_config_option(
18 NAME RMM_STATIC_ANALYSIS_CPPCHECK
19 HELP "Enable Cppcheck static analysis."
20 DEFAULT TRUE
21 DEPENDS (RMM_STATIC_ANALYSIS) AND
22 (EXISTS "${RMM_STATIC_ANALYSIS_CPPCHECK_PATH}")
23 ELSE FALSE)
24
25arm_config_option(
26 NAME RMM_STATIC_ANALYSIS_CPPCHECK_FLAGS
27 HELP "Cppcheck command line options."
28 TYPE STRING
29 DEFAULT ""
30 DEPENDS RMM_STATIC_ANALYSIS_CPPCHECK
31 ADVANCED)
32
33arm_config_option(
34 NAME RMM_STATIC_ANALYSIS_CPPCHECK_CHECKER_CERT_C
35 HELP "Enable Cppcheck's SEI CERT C checker."
36 DEFAULT TRUE
37 DEPENDS RMM_STATIC_ANALYSIS_CPPCHECK
38 ELSE FALSE)
39
40arm_config_option(
41 NAME RMM_STATIC_ANALYSIS_CPPCHECK_CHECKER_MISRA
42 HELP "Enable Cppcheck's MISRA C:2012 checker."
43 DEFAULT TRUE
44 DEPENDS RMM_STATIC_ANALYSIS_CPPCHECK
45 ELSE FALSE)
46
47arm_config_option(
48 NAME RMM_STATIC_ANALYSIS_CPPCHECK_CHECKER_THREAD_SAFETY
49 HELP "Enable Cppcheck's thread safety checker."
50 DEFAULT TRUE
51 DEPENDS RMM_STATIC_ANALYSIS_CPPCHECK
52 ELSE FALSE)
53
54if(RMM_STATIC_ANALYSIS_CPPCHECK)
55 #
56 # Set up checkers.
57 #
58
59 set(cppcheck-flags)
60
61 list(APPEND cppcheck-flags "--enable=all")
62 list(APPEND cppcheck-flags "--xml")
63 list(APPEND cppcheck-flags "--xml-version=2")
64 list(APPEND cppcheck-flags "--output-file=${CMAKE_CURRENT_BINARY_DIR}/cppcheck.xml")
65
66 if(RMM_STATIC_ANALYSIS_CPPCHECK_CHECKER_CERT_C)
67 list(APPEND cppcheck-flags "--addon=cert")
68 endif()
69
70 if(RMM_STATIC_ANALYSIS_CPPCHECK_CHECKER_MISRA)
71 list(APPEND cppcheck-flags "--addon=${CMAKE_CURRENT_SOURCE_DIR}/misra.json")
72 endif()
73
74 if(RMM_STATIC_ANALYSIS_CPPCHECK_CHECKER_THREAD_SAFETY)
75 list(APPEND cppcheck-flags "--addon=threadsafety")
76 endif()
77
78 #
79 # Pass CHAR_BIT to Mbed TLS to supress error:
80 # "mbed TLS requires a platform with 8-bit chars"
81 #
82
83 list(APPEND cppcheck-flags "-DCHAR_BIT=8")
84
85 #
86 # Suppress files or directories we don't want to receive warnings about. If
87 # you want to suppress specific files without using an inline suppression,
88 # do it in `suppressions.txt`.
89 #
90
91 list(APPEND cppcheck-flags
92 "--inline-suppr" # Allow inline suppressions
93 "--suppressions-list=${CMAKE_CURRENT_SOURCE_DIR}/suppressions.txt")
94
95 #
96 # Determine implicit C compiler definitions by pulling them from the
97 # compiler and dumping them into a header file. This is for those situations
98 # where we're relying on compiler implementation details, but Cppcheck
99 # doesn't expose them.
100 #
101
102 file(TOUCH "${CMAKE_CURRENT_BINARY_DIR}/null.txt")
103
104 separate_arguments(cflags NATIVE_COMMAND "${CMAKE_C_FLAGS}")
105
106 execute_process(
107 COMMAND ${CMAKE_C_COMPILER} ${cflags} -dM -E -
108 INPUT_FILE "${CMAKE_CURRENT_BINARY_DIR}/null.txt"
109 OUTPUT_FILE "${CMAKE_CURRENT_BINARY_DIR}/implicit-defines.h")
110
111 list(APPEND cppcheck-flags
112 "--include=${CMAKE_CURRENT_BINARY_DIR}/implicit-defines.h"
113 "--suppress=*:${CMAKE_CURRENT_BINARY_DIR}/implicit-defines.h")
114
115 #
116 # Traditionally we would let Cppcheck use its own standard library headers,
117 # but it appears to be lacking some critical symbols like `CHAR_BIT` from
118 # `<limits.h>`. Luckily, CMake makes this relatively easy for us to do. We
119 # don't analyze these headers, we just make them available for inclusion.
120 #
121
122 foreach(include IN LISTS CMAKE_C_IMPLICIT_INCLUDE_DIRECTORIES)
123 list(APPEND cppcheck-flags "-I${include}")
124 list(APPEND cppcheck-flags "--suppress=*:${include}/*")
125 endforeach()
126
127 #
128 # Configure the platform file. This is done based on the current compiler,
129 # if possible, so that we can communicate certain implementation details to
130 # Cppcheck and avoid false positives.
131 #
132
133 set(platform-xml
134 "${CMAKE_CURRENT_SOURCE_DIR}/compilers/${CMAKE_C_COMPILER_ID}.xml")
135
136 if(EXISTS "${platform-xml}")
137 list(APPEND cppcheck-flags "--platform=${platform-xml}")
138 else()
139 message(WARNING
140 "No Cppcheck platform file is available for this compiler. Static "
141 "analysis results may be inaccurate.")
142 endif()
143
144 separate_arguments(cppcheck-flags-user
145 NATIVE_COMMAND "${RMM_STATIC_ANALYSIS_CPPCHECK_FLAGS}")
146
147
148 set(COMPILE_COMMANDS_FILE "${CMAKE_BINARY_DIR}/compile_commands.json")
149
150 add_custom_target(cppcheck
151 COMMAND ${RMM_STATIC_ANALYSIS_CPPCHECK_PATH}
152 --project=${COMPILE_COMMANDS_FILE} ${cppcheck-flags} ||
153 (test ! -e ${COMPILE_COMMANDS_FILE} &&
154 echo 'please generate with -DRMM_STATIC_ANALYSIS_CPPCHECK=ON')
155 )
156else()
157 unset(CMAKE_C_CPPCHECK CACHE)
158endif()