blob: 7302bae8049db8324fa7d5eb58e6eeb32d2a4c91 [file] [log] [blame]
Alexei Frolove2016762019-11-14 13:49:52 -08001# Copyright 2019 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
Armando Montanezfb3d3fb2020-06-09 18:12:12 -070015import("//build_overrides/pigweed.gni")
16
Wyatt Hepler51ded742020-10-19 14:45:27 -070017import("$dir_pw_build/python_action.gni")
Wyatt Heplerd49f8fe2020-10-15 10:13:47 -070018
Alexei Frolov4c0428a2020-06-10 10:46:04 -070019declare_args() {
20 # Path to the Bloaty configuration file that defines the memory layout and
21 # capacities for the target binaries.
22 pw_bloat_BLOATY_CONFIG = ""
23
24 # List of toolchains to use in pw_toolchain_size_report templates.
25 #
26 # Each entry is a scope containing the following variables:
27 #
28 # name: Human-readable toolchain name.
29 # target: GN target that defines the toolchain.
30 # linker_script: Optional path to a linker script file to build for the
31 # toolchain's target.
32 # bloaty_config: Optional Bloaty confirugation file defining the memory
33 # layout of the binaries as specified in the linker script.
34 #
35 # If this list is empty, pw_toolchain_size_report targets become no-ops.
36 pw_bloat_TOOLCHAINS = []
37}
Alexei Frolove2016762019-11-14 13:49:52 -080038
39# Creates a target which runs a size report diff on a set of executables.
40#
41# Args:
Wyatt Hepler32d86bb2019-11-18 22:54:53 -080042# base: The default base executable target to run the diff against. May be
43# omitted if all binaries provide their own base.
Alexei Frolove2016762019-11-14 13:49:52 -080044# binaries: List of executables to compare in the diff.
45# Each binary in the list is a scope containing up to three variables:
46# label: Descriptive name for the executable. Required.
47# target: Build target for the executable. Required.
48# base: Optional base diff target. Overrides global base argument.
49# source_filter: Optional regex to filter data source names in Bloaty.
50# title: Optional title string to display with the size report.
51# full_report: Optional boolean flag indicating whether to produce a full
52# symbol size breakdown or a summary.
53#
54# Example:
Alexei Frolov09447842019-11-15 15:09:05 -080055# pw_size_report("foo_bloat") {
Alexei Frolove2016762019-11-14 13:49:52 -080056# base = ":foo_base"
57# binaries = [
58# {
59# target = ":foo_static"
60# label = "Static"
61# },
62# {
63# target = ":foo_dynamic"
64# label = "Dynamic"
65# },
66# ]
67# title = "static vs. dynamic foo"
68# }
69#
Alexei Frolov09447842019-11-15 15:09:05 -080070template("pw_size_report") {
Alexei Frolove4970e72020-06-11 13:55:29 -070071 if (pw_bloat_BLOATY_CONFIG != "") {
72 if (defined(invoker.base)) {
73 _global_base = invoker.base
74 _all_target_dependencies = [ _global_base ]
Wyatt Hepler32d86bb2019-11-18 22:54:53 -080075 } else {
Alexei Frolove4970e72020-06-11 13:55:29 -070076 _all_target_dependencies = []
Alexei Frolove2016762019-11-14 13:49:52 -080077 }
78
Alexei Frolove4970e72020-06-11 13:55:29 -070079 if (defined(invoker.title)) {
80 _title = invoker.title
Alexei Frolov3fde6b12019-12-18 16:13:38 -080081 } else {
Alexei Frolove4970e72020-06-11 13:55:29 -070082 _title = target_name
Alexei Frolov3fde6b12019-12-18 16:13:38 -080083 }
84
Alexei Frolove4970e72020-06-11 13:55:29 -070085 # This template creates an action which invokes a Python script to run a
86 # size report on each of the provided targets. Each of the targets is listed
87 # as a dependency of the action so that the report gets updated when
88 # anything is changed. Most of the code below builds the command-line
89 # arguments to pass each of the targets into the script.
Wyatt Hepler32d86bb2019-11-18 22:54:53 -080090
Alexei Frolove4970e72020-06-11 13:55:29 -070091 _binary_paths = []
92 _binary_labels = []
93 _bloaty_configs = []
Alexei Frolove2016762019-11-14 13:49:52 -080094
Alexei Frolove4970e72020-06-11 13:55:29 -070095 # Process each of the binaries, resolving their full output paths and
96 # building them into a list of command-line arguments to the bloat script.
97 foreach(binary, invoker.binaries) {
98 assert(defined(binary.label) && defined(binary.target),
99 "Size report binaries must define 'label' and 'target' variables")
100 _all_target_dependencies += [ binary.target ]
Alexei Frolove2016762019-11-14 13:49:52 -0800101
Wyatt Hepler8224a642020-07-29 08:55:56 -0700102 _binary_path = "<TARGET_FILE(${binary.target})>"
Alexei Frolove2016762019-11-14 13:49:52 -0800103
Alexei Frolove4970e72020-06-11 13:55:29 -0700104 # If the binary defines its own base, use that instead of the global base.
105 if (defined(binary.base)) {
106 _binary_base = binary.base
107 _all_target_dependencies += [ _binary_base ]
108 } else if (defined(_global_base)) {
109 _binary_base = _global_base
110 } else {
111 assert(false, "pw_size_report requires a 'base' file")
112 }
113
114 # Allow each binary to override the global bloaty config.
115 if (defined(binary.bloaty_config)) {
Alexei Frolovd27b6742020-08-19 10:54:56 -0700116 _bloaty_configs += [ rebase_path(binary.bloaty_config) ]
Alexei Frolove4970e72020-06-11 13:55:29 -0700117 } else {
Alexei Frolovd27b6742020-08-19 10:54:56 -0700118 _bloaty_configs += [ rebase_path(pw_bloat_BLOATY_CONFIG) ]
Alexei Frolove4970e72020-06-11 13:55:29 -0700119 }
120
Wyatt Hepler8224a642020-07-29 08:55:56 -0700121 _binary_path += ";" + "<TARGET_FILE($_binary_base)>"
Alexei Frolove4970e72020-06-11 13:55:29 -0700122
123 _binary_paths += [ _binary_path ]
124 _binary_labels += [ binary.label ]
125 }
126
127 _bloat_script_args = [
128 "--bloaty-config",
129 string_join(";", _bloaty_configs),
130 "--out-dir",
Alexei Frolovd27b6742020-08-19 10:54:56 -0700131 rebase_path(target_gen_dir),
Alexei Frolove4970e72020-06-11 13:55:29 -0700132 "--target",
133 target_name,
134 "--title",
135 _title,
136 "--labels",
137 string_join(";", _binary_labels),
Alexei Frolove2016762019-11-14 13:49:52 -0800138 ]
Alexei Frolove2016762019-11-14 13:49:52 -0800139
Alexei Frolove4970e72020-06-11 13:55:29 -0700140 if (defined(invoker.full_report) && invoker.full_report) {
141 _bloat_script_args += [ "--full" ]
Alexei Frolov3adcd672020-03-19 09:45:33 -0700142 }
Alexei Frolov844ff0f2020-05-06 12:15:29 -0700143
Alexei Frolove4970e72020-06-11 13:55:29 -0700144 if (defined(invoker.source_filter)) {
145 _bloat_script_args += [
146 "--source-filter",
147 invoker.source_filter,
148 ]
149 }
150
151 _doc_rst_output = "$target_gen_dir/${target_name}"
152
Alexei Frolovd27b6742020-08-19 10:54:56 -0700153 if (host_os == "win") {
Alexei Frolove4970e72020-06-11 13:55:29 -0700154 # Bloaty is not yet packaged for Windows systems; display a message
155 # indicating this.
156 not_needed("*")
157 not_needed(invoker, "*")
158
Wyatt Heplerc8e05a42020-10-19 14:49:39 -0700159 pw_python_action(target_name) {
Alexei Frolove4970e72020-06-11 13:55:29 -0700160 metadata = {
161 pw_doc_sources = rebase_path([ _doc_rst_output ], root_build_dir)
162 }
163 script = "$dir_pw_bloat/py/no_bloaty.py"
Wyatt Hepler8224a642020-07-29 08:55:56 -0700164 args = [ rebase_path(_doc_rst_output) ]
Alexei Frolove4970e72020-06-11 13:55:29 -0700165 outputs = [ _doc_rst_output ]
166 }
167
168 group(target_name + "_UNUSED_DEPS") {
169 deps = _all_target_dependencies
170 }
171 } else {
172 # Create an action which runs the size report script on the provided
173 # targets.
Wyatt Heplerc8e05a42020-10-19 14:49:39 -0700174 pw_python_action(target_name) {
Alexei Frolove4970e72020-06-11 13:55:29 -0700175 metadata = {
176 pw_doc_sources = rebase_path([ _doc_rst_output ], root_build_dir)
177 }
178 script = "$dir_pw_bloat/py/bloat.py"
179 inputs = [
180 "$dir_pw_bloat/py/binary_diff.py",
181 "$dir_pw_bloat/py/bloat_output.py",
182 ] + _bloaty_configs
183 outputs = [
184 "$target_gen_dir/${target_name}.txt",
185 _doc_rst_output,
186 ]
187 deps = _all_target_dependencies
188 args = _bloat_script_args + _binary_paths
189
190 # Print size reports to stdout when they are generated.
191 capture_output = false
192 }
Alexei Frolov844ff0f2020-05-06 12:15:29 -0700193 }
Alexei Frolov3adcd672020-03-19 09:45:33 -0700194 } else {
Alexei Frolove4970e72020-06-11 13:55:29 -0700195 not_needed(invoker, "*")
196 group(target_name) {
Alexei Frolov3adcd672020-03-19 09:45:33 -0700197 }
Alexei Frolove2016762019-11-14 13:49:52 -0800198 }
199}
Alexei Frolov3fde6b12019-12-18 16:13:38 -0800200
201# Creates a report card comparing the sizes of the same binary compiled with
202# different toolchains. The toolchains to use are listed in the build variable
Alexei Frolov4c0428a2020-06-10 10:46:04 -0700203# pw_bloat_TOOLCHAINS.
Alexei Frolov3fde6b12019-12-18 16:13:38 -0800204#
205# Args:
206# base_executable: Scope containing a list of variables defining an executable
207# target for the size report base.
208# diff_executable: Scope containing a list of variables defining an executable
209# target for the size report comparison.
210#
211# Outputs:
212# $target_gen_dir/$target_name.txt
213# $target_gen_dir/$target_name.rst
214#
215# Example:
216#
217# pw_toolchain_size_report("my_size_report") {
218# base_executable = {
219# sources = [ "base.cc" ]
220# }
221#
222# diff_executable = {
223# sources = [ "base_with_libfoo.cc" ]
224# deps = [ ":libfoo" ]
225# }
226# }
227#
228template("pw_toolchain_size_report") {
229 assert(defined(invoker.base_executable),
230 "pw_toolchain_size_report requires a base_executable")
231 assert(defined(invoker.diff_executable),
232 "pw_toolchain_size_report requires a diff_executable")
233
234 _size_report_binaries = []
235
236 # Multiple build targets are created for each toolchain, which all need unique
237 # target names, so throw a counter in there.
238 i = 0
239
240 # Create a base and diff executable for each toolchain, adding the toolchain's
241 # linker script to the link flags for the executable, and add them all to a
242 # list of binaries for the pw_size_report template.
Alexei Frolov4c0428a2020-06-10 10:46:04 -0700243 foreach(_toolchain, pw_bloat_TOOLCHAINS) {
Alexei Frolov3fde6b12019-12-18 16:13:38 -0800244 _prefix = "_${target_name}_${i}_pw_size"
245
246 # Create a config which adds the toolchain's linker script as a linker flag
247 # if the toolchain provides one.
248 _linker_script_target_name = "${_prefix}_linker_script"
249 config(_linker_script_target_name) {
250 if (defined(_toolchain.linker_script)) {
251 ldflags = [ "-T" + rebase_path(_toolchain.linker_script) ]
Alexei Frolov47373492020-03-03 16:37:11 -0800252 inputs = [ _toolchain.linker_script ]
Alexei Frolov3fde6b12019-12-18 16:13:38 -0800253 } else {
254 ldflags = []
255 }
256 }
257
258 # Create a group which forces the linker script config its dependents.
259 _linker_group_target_name = "${_prefix}_linker_group"
260 group(_linker_group_target_name) {
261 public_configs = [ ":$_linker_script_target_name" ]
262 }
263
264 # Define the size report base executable with the toolchain's linker script.
265 _base_target_name = "${_prefix}_base"
266 executable(_base_target_name) {
267 forward_variables_from(invoker.base_executable, "*")
268 if (!defined(deps)) {
269 deps = []
270 }
271 deps += [ ":$_linker_group_target_name" ]
272 }
273
274 # Define the size report diff executable with the toolchain's linker script.
275 _diff_target_name = "${_prefix}_diff"
276 executable(_diff_target_name) {
277 forward_variables_from(invoker.diff_executable, "*")
278 if (!defined(deps)) {
279 deps = []
280 }
281 deps += [ ":$_linker_group_target_name" ]
282 }
283
284 # Force compilation with the toolchain.
285 _base_label = get_label_info(":$_base_target_name", "label_no_toolchain")
286 _base_with_toolchain = "$_base_label(${_toolchain.target})"
287 _diff_label = get_label_info(":$_diff_target_name", "label_no_toolchain")
288 _diff_with_toolchain = "$_diff_label(${_toolchain.target})"
289
290 # Append a pw_size_report binary scope to the list comparing the toolchain's
291 # diff and base executables.
292 _size_report_binaries += [
293 {
294 base = _base_with_toolchain
295 target = _diff_with_toolchain
296 label = _toolchain.name
297
298 if (defined(_toolchain.bloaty_config)) {
299 bloaty_config = _toolchain.bloaty_config
300 }
301 },
302 ]
303
304 i += 1
305 }
306
Alexei Frolov844ff0f2020-05-06 12:15:29 -0700307 # TODO(frolv): Have a way of indicating that a toolchain should build docs.
308 if (current_toolchain == default_toolchain && _size_report_binaries != []) {
Alexei Frolov3fde6b12019-12-18 16:13:38 -0800309 # Create the size report which runs on the binaries.
310 pw_size_report(target_name) {
311 forward_variables_from(invoker, [ "title" ])
312 binaries = _size_report_binaries
313 }
314 } else {
Alexei Frolov4c0428a2020-06-10 10:46:04 -0700315 # If no toolchains are listed in pw_bloat_TOOLCHAINS, prevent GN from
Alexei Frolov3fde6b12019-12-18 16:13:38 -0800316 # complaining about unused variables and run a script that outputs a ReST
317 # warning to the size report file.
318 not_needed("*")
319 not_needed(invoker, "*")
320
Alexei Frolov725b85b2020-03-19 13:37:10 -0700321 _doc_rst_output = "$target_gen_dir/$target_name"
Wyatt Heplerc8e05a42020-10-19 14:49:39 -0700322 pw_python_action(target_name) {
Alexei Frolov3fde6b12019-12-18 16:13:38 -0800323 metadata = {
324 pw_doc_sources = rebase_path([ _doc_rst_output ], root_build_dir)
325 }
326 script = "$dir_pw_bloat/py/no_toolchains.py"
Wyatt Hepler8224a642020-07-29 08:55:56 -0700327 args = [ rebase_path(_doc_rst_output) ]
Rob Mohra0ba54f2020-02-27 11:43:49 -0800328 outputs = [ _doc_rst_output ]
Alexei Frolov3fde6b12019-12-18 16:13:38 -0800329 }
330 }
331}
Alexei Frolovf8259f62020-01-09 12:35:36 -0800332
333# A base_executable for the pw_toolchain_size_report template which contains a
334# main() function that loads the bloat_this_binary library and does nothing
335# else.
336pw_bloat_empty_base = {
Wyatt Heplerc5e511e2020-06-12 16:56:22 -0700337 deps = [
338 "$dir_pw_bloat:base_main",
339 "$dir_pw_bloat:bloat_this_binary",
340 ]
Alexei Frolovf8259f62020-01-09 12:35:36 -0800341}