blob: 732f2094d4520a4caa16cd50e478a73709774f9b [file] [log] [blame]
Henri Chataing19e41f02021-08-10 11:04:30 +02001# Copyright 2021 The Pigweed Authors
2#
3# Licensed under the Apache License, Version 2.0 (the "License"); you may not
4# use this file except in compliance with the License. You may obtain a copy of
5# the License at
6#
7# https://www.apache.org/licenses/LICENSE-2.0
8#
9# Unless required by applicable law or agreed to in writing, software
10# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
11# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
12# License for the specific language governing permissions and limitations under
13# the License.
14
15import("//build_overrides/pigweed.gni")
16
17import("$dir_pw_toolchain/universal_tools.gni")
18
19declare_args() {
Ted Pudlik73d948c2021-10-26 19:44:17 +000020 # Regular expressions matching the paths of the source files to be excluded
Henri Chataingdd465872021-09-01 15:41:21 +000021 # from the analysis. clang-tidy provides no alternative option.
Henri Chataing19e41f02021-08-10 11:04:30 +020022 #
Wyatt Hepler5e9f7a62021-10-08 21:04:10 -070023 # For example, the following disables clang-tidy on all source files in the
24 # third_party directory:
Henri Chataing19e41f02021-08-10 11:04:30 +020025 #
Ted Pudlik73d948c2021-10-26 19:44:17 +000026 # pw_toolchain_STATIC_ANALYSIS_SKIP_SOURCES_RES = ["third_party/.*"]
Wyatt Hepler5e9f7a62021-10-08 21:04:10 -070027 #
Ted Pudlik73d948c2021-10-26 19:44:17 +000028 pw_toolchain_STATIC_ANALYSIS_SKIP_SOURCES_RES = []
Wyatt Hepler5e9f7a62021-10-08 21:04:10 -070029
30 # Disable clang-tidy for specific include paths. In the clang-tidy command,
Scott James Remnant4d28e222022-02-16 12:01:25 -080031 # include paths that end with one of these, or match as a regular expression,
32 # are switched from -I to -isystem, which causes clang-tidy to ignore them.
33 # Unfortunately, clang-tidy provides no other way to filter header files.
Wyatt Hepler5e9f7a62021-10-08 21:04:10 -070034 #
35 # For example, the following ignores header files in "mbedtls/include":
36 #
37 # pw_toolchain_STATIC_ANALYSIS_SKIP_INCLUDE_PATHS = ["mbedtls/include"]
38 #
Scott James Remnant4d28e222022-02-16 12:01:25 -080039 # While the following ignores all third-party header files:
40 #
41 # pw_toolchain_STATIC_ANALYSIS_SKIP_INCLUDE_PATHS = [".*/third_party/.*"]
42 #
Wyatt Hepler5e9f7a62021-10-08 21:04:10 -070043 pw_toolchain_STATIC_ANALYSIS_SKIP_INCLUDE_PATHS = []
Henri Chataing19e41f02021-08-10 11:04:30 +020044}
45
46# Creates a toolchain target for static analysis.
Ted Pudlik17d5e712021-10-25 20:43:54 +000047#
48# The generated toolchain runs clang-tidy on all source files that are not
Ted Pudlik73d948c2021-10-26 19:44:17 +000049# excluded by pw_toolchain_STATIC_ANALYSIS_SKIP_SOURCES_RES or
Ted Pudlik17d5e712021-10-25 20:43:54 +000050# pw_toolchain_STATIC_ANALYSIS_SKIP_INCLUDE_PATHS.
Henri Chataing19e41f02021-08-10 11:04:30 +020051#
52# Args:
53# cc: (required) String indicating the C compiler to use.
54# cxx: (required) String indicating the C++ compiler to use.
55template("pw_static_analysis_toolchain") {
Henri Chataing19e41f02021-08-10 11:04:30 +020056 invoker_toolchain_args = invoker.defaults
Henri Chataing19e41f02021-08-10 11:04:30 +020057
58 # Clang tidy is invoked by a wrapper script which implements the missing
59 # option --source-filter.
60 _clang_tidy_py_path =
Henri Chataingdd465872021-09-01 15:41:21 +000061 rebase_path("$dir_pw_toolchain/py/pw_toolchain/clang_tidy.py",
62 root_build_dir)
Henri Chataing19e41f02021-08-10 11:04:30 +020063 _clang_tidy_py = "${python_path} ${_clang_tidy_py_path}"
Henri Chataingdd465872021-09-01 15:41:21 +000064 _source_root = rebase_path("//", root_build_dir)
65 _source_exclude = ""
Ted Pudlik73d948c2021-10-26 19:44:17 +000066 foreach(pattern, pw_toolchain_STATIC_ANALYSIS_SKIP_SOURCES_RES) {
Henri Chataingdd465872021-09-01 15:41:21 +000067 _source_exclude = _source_exclude + " --source-exclude '${pattern}'"
68 }
Henri Chataing19e41f02021-08-10 11:04:30 +020069
Wyatt Hepler5e9f7a62021-10-08 21:04:10 -070070 _skip_include_path =
71 "--skip-include-path " +
72 string_join(" ", pw_toolchain_STATIC_ANALYSIS_SKIP_INCLUDE_PATHS)
73
Henri Chataing19e41f02021-08-10 11:04:30 +020074 toolchain(target_name) {
75 # Uncomment this line to see which toolchains generate other toolchains.
76 # print("Generating toolchain: ${target_name} by ${current_toolchain}")
77
78 tool("asm") {
79 depfile = "{{output}}.d"
80 command = pw_universal_stamp.command
81 depsformat = "gcc"
82 description = "as {{output}}"
83 outputs = [
84 # Use {{source_file_part}}, which includes the extension, instead of
85 # {{source_name_part}} so that object files created from <file_name>.c
86 # and <file_name>.cc sources are unique.
87 "{{source_out_dir}}/{{target_output_name}}.{{source_file_part}}.o",
88 ]
89 }
90
91 assert(defined(invoker.cc), "toolchain is missing 'cc'")
92 tool("cc") {
93 depfile = "{{output}}.d"
94 command = string_join(" ",
95 [
96 _clang_tidy_py,
Henri Chataingdd465872021-09-01 15:41:21 +000097 _source_exclude,
Wyatt Hepler5e9f7a62021-10-08 21:04:10 -070098 _skip_include_path,
Henri Chataing19e41f02021-08-10 11:04:30 +020099 "--source-file {{source}}",
Henri Chataingdd465872021-09-01 15:41:21 +0000100 "--source-root '${_source_root}'",
Henri Chataing19e41f02021-08-10 11:04:30 +0200101 "--export-fixes {{output}}.yaml",
102 "--",
103 invoker.cc,
104 "-MMD -MF $depfile", # Write out dependencies.
105 "{{cflags}}",
106 "{{cflags_c}}", # Must come after {{cflags}}.
107 "{{defines}}",
108 "{{include_dirs}}",
109 "-c {{source}}",
110 "-o {{output}}",
111 ]) + " && touch {{output}}"
112 depsformat = "gcc"
113 description = "clang-tidy {{source}}"
114 outputs =
115 [ "{{source_out_dir}}/{{target_output_name}}.{{source_file_part}}.o" ]
116 }
117
118 assert(defined(invoker.cxx), "toolchain is missing 'cxx'")
119 tool("cxx") {
120 depfile = "{{output}}.d"
121 command = string_join(" ",
122 [
123 _clang_tidy_py,
Henri Chataingdd465872021-09-01 15:41:21 +0000124 _source_exclude,
Wyatt Hepler5e9f7a62021-10-08 21:04:10 -0700125 _skip_include_path,
Henri Chataing19e41f02021-08-10 11:04:30 +0200126 "--source-file {{source}}",
Henri Chataingdd465872021-09-01 15:41:21 +0000127 "--source-root '${_source_root}'",
Henri Chataing19e41f02021-08-10 11:04:30 +0200128 "--export-fixes {{output}}.yaml",
129 "--",
130 invoker.cxx,
131 "-MMD -MF $depfile", # Write out dependencies.
132 "{{cflags}}",
133 "{{cflags_cc}}", # Must come after {{cflags}}.
134 "{{defines}}",
135 "{{include_dirs}}",
136 "-c {{source}}",
137 "-o {{output}}",
138 ]) + " && touch {{output}}"
139 depsformat = "gcc"
140 description = "clang-tidy {{source}}"
141 outputs =
142 [ "{{source_out_dir}}/{{target_output_name}}.{{source_file_part}}.o" ]
143 }
144
145 tool("objc") {
146 depfile = "{{output}}.d"
147 command = pw_universal_stamp.command
148 depsformat = "gcc"
149 description = "objc {{source}}"
150 outputs =
151 [ "{{source_out_dir}}/{{target_output_name}}.{{source_file_part}}.o" ]
152 }
153
154 tool("objcxx") {
155 depfile = "{{output}}.d"
156 command = pw_universal_stamp.command
157 depsformat = "gcc"
158 description = "objc++ {{output}}"
159 outputs =
160 [ "{{source_out_dir}}/{{target_output_name}}.{{source_file_part}}.o" ]
161 }
162
163 tool("alink") {
164 command = "rm -f {{output}} && touch {{output}}"
165 description = "ar {{target_output_name}}{{output_extension}}"
166 outputs = [ "{{output_dir}}/{{target_output_name}}{{output_extension}}" ]
167 default_output_extension = ".a"
168 default_output_dir = "{{target_out_dir}}/lib"
169 }
170
171 tool("link") {
172 if (host_os == "win") {
173 # Force the extension to '.bat', empty bat scripts are still
174 # executable and will not raise errors.
175 _output = "{{output_dir}}/{{target_output_name}}.bat"
176 command = pw_universal_stamp.command
177 default_output_extension = ".bat"
178 } else {
179 default_output_extension = ""
180 _output = "{{output_dir}}/{{target_output_name}}{{output_extension}}"
181 command = "touch {{output}} && chmod +x {{output}}"
182 }
183 description = "ld $_output"
184 outputs = [ _output ]
185 default_output_dir = "{{target_out_dir}}/bin"
186 }
187
188 tool("solink") {
189 _output = "{{output_dir}}/{{target_output_name}}{{output_extension}}"
190 command = pw_universal_stamp.command
191 description = "ld -shared $_output"
192 outputs = [ _output ]
193 default_output_dir = "{{target_out_dir}}/lib"
194 default_output_extension = ".so"
195 }
196
197 tool("stamp") {
198 # GN-ism: GN gets mad if you directly forward the contents of
199 # pw_universal_stamp.
200 _stamp = pw_universal_stamp
201 forward_variables_from(_stamp, "*")
202 }
203
204 tool("copy") {
205 # GN-ism: GN gets mad if you directly forward the contents of
206 # pw_universal_copy.
207 _copy = pw_universal_copy
208 forward_variables_from(_copy, "*")
209 }
210
211 # Build arguments to be overridden when compiling cross-toolchain:
212 #
213 # pw_toolchain_defaults: A scope setting defaults to apply to GN targets
214 # in this toolchain. It is analogous to $pw_target_defaults in
215 # $dir_pigweed/pw_vars_default.gni.
216 #
217 # pw_toolchain_SCOPE: A copy of the invoker scope that defines the
218 # toolchain. Used for generating derivative toolchains.
219 #
220 toolchain_args = {
221 pw_toolchain_SCOPE = {
222 }
223 pw_toolchain_SCOPE = {
224 forward_variables_from(invoker, "*")
225 name = target_name
226 }
227 forward_variables_from(invoker_toolchain_args, "*")
228 }
229 }
230}