aboutsummaryrefslogtreecommitdiff
path: root/pw_bloat/bloat.gni
diff options
context:
space:
mode:
Diffstat (limited to 'pw_bloat/bloat.gni')
-rw-r--r--pw_bloat/bloat.gni329
1 files changed, 276 insertions, 53 deletions
diff --git a/pw_bloat/bloat.gni b/pw_bloat/bloat.gni
index 661df3202..52a3a3f80 100644
--- a/pw_bloat/bloat.gni
+++ b/pw_bloat/bloat.gni
@@ -1,4 +1,4 @@
-# Copyright 2019 The Pigweed Authors
+# Copyright 2023 The Pigweed Authors
#
# Licensed under the Apache License, Version 2.0 (the "License"); you may not
# use this file except in compliance with the License. You may obtain a copy of
@@ -14,6 +14,7 @@
import("//build_overrides/pigweed.gni")
+import("$dir_pw_build/evaluate_path_expressions.gni")
import("$dir_pw_build/python_action.gni")
declare_args() {
@@ -21,7 +22,7 @@ declare_args() {
# capacities for the target binaries.
pw_bloat_BLOATY_CONFIG = ""
- # List of toolchains to use in pw_toolchain_size_report templates.
+ # List of toolchains to use in pw_toolchain_size_diff templates.
#
# Each entry is a scope containing the following variables:
#
@@ -32,31 +33,214 @@ declare_args() {
# bloaty_config: Optional Bloaty confirugation file defining the memory
# layout of the binaries as specified in the linker script.
#
- # If this list is empty, pw_toolchain_size_report targets become no-ops.
+ # If this list is empty, pw_toolchain_size_diff targets become no-ops.
pw_bloat_TOOLCHAINS = []
# Controls whether to display size reports in the build output.
pw_bloat_SHOW_SIZE_REPORTS = false
}
+# Creates a size report for a single binary.
+#
+# Args:
+# target: Build target for executable. Required.
+# data_sources: List of datasources from bloaty config file
+# or built-in datasources. Order of sources determines hierarchical
+# output. Optional.
+# github.com/google/bloaty/blob/a1bbc93f5f6f969242046dffd9deb379f6735020/doc/using.md
+# source_filter: Regex to filter data source names in Bloaty. Optional.
+#
+# Example:
+# pw_size_report("foo_bloat") {
+# target = ":foo_static"
+# datasources = "symbols,segment_names"
+# source_filter = "foo"
+# }
+#
+template("pw_size_report") {
+ if (pw_bloat_BLOATY_CONFIG != "") {
+ assert(defined(invoker.target),
+ "Size report must defined a 'target' variable")
+ _all_target_dependencies = [ invoker.target ]
+ _binary_args = []
+
+ if (defined(invoker.source_filter)) {
+ curr_source_filter = invoker.source_filter
+ } else {
+ curr_source_filter = ""
+ }
+
+ if (defined(invoker.data_sources)) {
+ curr_data_sources = string_split(invoker.data_sources, ",")
+ } else {
+ curr_data_sources = ""
+ }
+ _binary_args = [
+ {
+ bloaty_config = rebase_path(pw_bloat_BLOATY_CONFIG, root_build_dir)
+ out_dir = rebase_path(target_gen_dir, root_build_dir)
+ target = "<TARGET_FILE(${invoker.target})>"
+ source_filter = curr_source_filter
+ data_sources = curr_data_sources
+ },
+ ]
+
+ _file_name = "${target_name}_single_binary.json"
+
+ _args_src = "$target_gen_dir/${_file_name}.in"
+ _args_path = "$target_gen_dir/${_file_name}"
+
+ write_file(_args_src,
+ {
+ binaries = _binary_args
+ target_name = target_name
+ out_dir = rebase_path(target_gen_dir, root_build_dir)
+ root = rebase_path("//", root_build_dir)
+ toolchain = current_toolchain
+ default_toolchain = default_toolchain
+ cwd = rebase_path(".", root_build_dir)
+ },
+ "json")
+
+ pw_evaluate_path_expressions("${target_name}.evaluate") {
+ files = [
+ {
+ source = _args_src
+ dest = _args_path
+ },
+ ]
+ }
+
+ _bloat_script_args = [
+ "--gn-arg-path",
+ rebase_path(_args_path, root_build_dir),
+ "--single-report",
+ ]
+
+ _doc_rst_output = "$target_gen_dir/${target_name}"
+ _binary_sizes_output = "$target_gen_dir/${target_name}.binary_sizes.json"
+
+ if (host_os == "win") {
+ # Bloaty is not yet packaged for Windows systems; display a message
+ # indicating this.
+ not_needed("*")
+ not_needed(invoker, "*")
+
+ pw_python_action(target_name) {
+ metadata = {
+ pw_doc_sources = rebase_path([ _doc_rst_output ], root_build_dir)
+ }
+ script = "$dir_pw_bloat/py/pw_bloat/no_bloaty.py"
+ python_deps = [ "$dir_pw_bloat/py" ]
+ args = [ rebase_path(_doc_rst_output, root_build_dir) ]
+ outputs = [ _doc_rst_output ]
+ }
+
+ group(target_name + "_UNUSED_DEPS") {
+ deps = _all_target_dependencies
+ }
+ } else {
+ # Create an action which runs the size report script on the provided
+ # targets.
+ pw_python_action(target_name) {
+ metadata = {
+ pw_doc_sources = rebase_path([ _doc_rst_output ], root_build_dir)
+ }
+ script = "$dir_pw_bloat/py/pw_bloat/bloat.py"
+ python_deps = [ "$dir_pw_bloat/py" ]
+ inputs = [
+ pw_bloat_BLOATY_CONFIG,
+ _args_path,
+ ]
+ outputs = [
+ "${_doc_rst_output}.txt",
+ _binary_sizes_output,
+ _doc_rst_output,
+ ]
+ deps = _all_target_dependencies + [ ":${target_name}.evaluate" ]
+ args = _bloat_script_args
+
+ # Print size reports to stdout when they are generated, if requested.
+ capture_output = !pw_bloat_SHOW_SIZE_REPORTS
+ }
+ }
+ } else {
+ not_needed(invoker, "*")
+ group(target_name) {
+ }
+ }
+}
+
+# Aggregates JSON size report data from several pw_size_report targets into a
+# single output file.
+#
+# Args:
+# deps: List of pw_size_report targets whose data to collect.
+# output: Path to the output JSON file.
+#
+# Example:
+# pw_size_report_aggregation("image_sizes") {
+# deps = [
+# ":app_image_size_report",
+# ":bootloader_image_size_report",
+# ]
+# output = "$root_gen_dir/artifacts/image_sizes.json"
+# }
+#
+template("pw_size_report_aggregation") {
+ assert(defined(invoker.deps) && invoker.deps != [],
+ "pw_size_report_aggregation requires size report dependencies")
+ assert(defined(invoker.output),
+ "pw_size_report_aggregation requires an output file path")
+
+ _input_json_files = []
+
+ foreach(_dep, invoker.deps) {
+ _gen_dir = get_label_info(_dep, "target_gen_dir")
+ _dep_name = get_label_info(_dep, "name")
+ _input_json_files +=
+ [ rebase_path("$_gen_dir/${_dep_name}.binary_sizes.json",
+ root_build_dir) ]
+ }
+
+ pw_python_action(target_name) {
+ script = "$dir_pw_bloat/py/pw_bloat/binary_size_aggregator.py"
+ python_deps = [ "$dir_pw_bloat/py" ]
+ args = [
+ "--output",
+ rebase_path(invoker.output, root_build_dir),
+ ] + _input_json_files
+ outputs = [ invoker.output ]
+ deps = invoker.deps
+ forward_variables_from(invoker, [ "visibility" ])
+ }
+}
+
# Creates a target which runs a size report diff on a set of executables.
#
# Args:
# base: The default base executable target to run the diff against. May be
# omitted if all binaries provide their own base.
+# source_filter: Optional global regex to filter data source names in Bloaty.
+# data_sources: List of datasources from bloaty config file
+# or built-in datasources. Order of sources determines hierarchical
+# output. Optional.
+# github.com/google/bloaty/blob/a1bbc93f5f6f969242046dffd9deb379f6735020/doc/using.md
# binaries: List of executables to compare in the diff.
# Each binary in the list is a scope containing up to three variables:
# label: Descriptive name for the executable. Required.
# target: Build target for the executable. Required.
# base: Optional base diff target. Overrides global base argument.
-# source_filter: Optional regex to filter data source names in Bloaty.
-# title: Optional title string to display with the size report.
-# full_report: Optional boolean flag indicating whether to produce a full
-# symbol size breakdown or a summary.
+# source_filter: Optional regex to filter data source names.
+# Overrides global source_filter argument.
+# data_sources: Optional List of datasources from bloaty config file
+# Overrides global data_sources argument.
+#
#
# Example:
-# pw_size_report("foo_bloat") {
+# pw_size_diff("foo_bloat") {
# base = ":foo_base"
+# data_sources = "segment,symbols"
# binaries = [
# {
# target = ":foo_static"
@@ -65,12 +249,12 @@ declare_args() {
# {
# target = ":foo_dynamic"
# label = "Dynamic"
+# data_sources = "segment_names"
# },
# ]
-# title = "static vs. dynamic foo"
# }
#
-template("pw_size_report") {
+template("pw_size_diff") {
if (pw_bloat_BLOATY_CONFIG != "") {
if (defined(invoker.base)) {
_global_base = invoker.base
@@ -79,10 +263,17 @@ template("pw_size_report") {
_all_target_dependencies = []
}
+ if (defined(invoker.source_filter)) {
+ _global_source_filter = invoker.source_filter
+ }
+
+ if (defined(invoker.data_sources)) {
+ _global_data_sources = string_split(invoker.data_sources, ",")
+ }
+
+ # TODO(brandonvu): Remove once all downstream projects are updated
if (defined(invoker.title)) {
- _title = invoker.title
- } else {
- _title = target_name
+ not_needed(invoker, [ "title" ])
}
# This template creates an action which invokes a Python script to run a
@@ -91,19 +282,16 @@ template("pw_size_report") {
# anything is changed. Most of the code below builds the command-line
# arguments to pass each of the targets into the script.
- _binary_paths = []
- _binary_labels = []
+ # Process each of the binaries, creating an object and storing all the
+ # needed variables into a json. Json is parsed in bloat.py
+ _binaries_args = []
_bloaty_configs = []
- # Process each of the binaries, resolving their full output paths and
- # building them into a list of command-line arguments to the bloat script.
foreach(binary, invoker.binaries) {
assert(defined(binary.label) && defined(binary.target),
"Size report binaries must define 'label' and 'target' variables")
_all_target_dependencies += [ binary.target ]
- _binary_path = "<TARGET_FILE(${binary.target})>"
-
# If the binary defines its own base, use that instead of the global base.
if (defined(binary.base)) {
_binary_base = binary.base
@@ -111,44 +299,79 @@ template("pw_size_report") {
} else if (defined(_global_base)) {
_binary_base = _global_base
} else {
- assert(false, "pw_size_report requires a 'base' file")
+ assert(false, "pw_size_diff requires a 'base' file")
+ }
+
+ if (defined(binary.source_filter)) {
+ _binary_source_filter = binary.source_filter
+ } else if (defined(_global_source_filter)) {
+ _binary_source_filter = _global_source_filter
+ } else {
+ _binary_source_filter = ""
+ }
+
+ _binary_data_sources = []
+ if (defined(binary.data_sources)) {
+ _binary_data_sources = string_split(binary.data_sources, ",")
+ } else if (defined(_global_data_sources)) {
+ _binary_data_sources = _global_data_sources
+ } else {
+ _binary_data_sources = ""
}
# Allow each binary to override the global bloaty config.
if (defined(binary.bloaty_config)) {
+ _binary_bloaty_config = binary.bloaty_config
_bloaty_configs += [ binary.bloaty_config ]
} else {
+ _binary_bloaty_config = pw_bloat_BLOATY_CONFIG
_bloaty_configs += [ pw_bloat_BLOATY_CONFIG ]
}
- _binary_path += ";" + "<TARGET_FILE($_binary_base)>"
+ _binaries_args += [
+ {
+ bloaty_config = rebase_path(_binary_bloaty_config, root_build_dir)
+ target = "<TARGET_FILE(${binary.target})>"
+ base = "<TARGET_FILE($_binary_base)>"
+ source_filter = _binary_source_filter
+ label = binary.label
+ data_sources = _binary_data_sources
+ },
+ ]
+ }
- _binary_paths += [ _binary_path ]
- _binary_labels += [ binary.label ]
+ _file_name = "${target_name}_binaries.json"
+ _diff_source = "$target_gen_dir/${_file_name}.in"
+ _diff_path = "$target_gen_dir/${_file_name}"
+ write_file(_diff_source,
+ {
+ binaries = _binaries_args
+ target_name = target_name
+ out_dir = rebase_path(target_gen_dir, root_build_dir)
+ root = rebase_path("//", root_build_dir)
+ toolchain = current_toolchain
+ default_toolchain = default_toolchain
+ cwd = rebase_path(".", root_build_dir)
+ },
+ "json")
+
+ pw_evaluate_path_expressions("${target_name}.evaluate") {
+ files = [
+ {
+ source = _diff_source
+ dest = _diff_path
+ },
+ ]
}
_bloat_script_args = [
- "--bloaty-config",
- string_join(";", rebase_path(_bloaty_configs, root_build_dir)),
- "--out-dir",
- rebase_path(target_gen_dir, root_build_dir),
- "--target",
- target_name,
- "--title",
- _title,
- "--labels",
- string_join(";", _binary_labels),
+ "--gn-arg-path",
+ rebase_path(_diff_path, root_build_dir),
]
- if (defined(invoker.full_report) && invoker.full_report) {
- _bloat_script_args += [ "--full" ]
- }
-
- if (defined(invoker.source_filter)) {
- _bloat_script_args += [
- "--source-filter",
- invoker.source_filter,
- ]
+ # TODO(brandonvu): Remove once all downstream projects are updated
+ if (defined(invoker.full_report)) {
+ not_needed(invoker, [ "full_report" ])
}
_doc_rst_output = "$target_gen_dir/${target_name}"
@@ -181,13 +404,13 @@ template("pw_size_report") {
}
script = "$dir_pw_bloat/py/pw_bloat/bloat.py"
python_deps = [ "$dir_pw_bloat/py" ]
- inputs = _bloaty_configs
+ inputs = _bloaty_configs + [ _diff_path ]
outputs = [
"${_doc_rst_output}.txt",
_doc_rst_output,
]
- deps = _all_target_dependencies
- args = _bloat_script_args + _binary_paths
+ deps = _all_target_dependencies + [ ":${target_name}.evaluate" ]
+ args = _bloat_script_args
# Print size reports to stdout when they are generated, if requested.
capture_output = !pw_bloat_SHOW_SIZE_REPORTS
@@ -216,7 +439,7 @@ template("pw_size_report") {
#
# Example:
#
-# pw_toolchain_size_report("my_size_report") {
+# pw_toolchain_size_diff("my_size_report") {
# base_executable = {
# sources = [ "base.cc" ]
# }
@@ -227,11 +450,11 @@ template("pw_size_report") {
# }
# }
#
-template("pw_toolchain_size_report") {
+template("pw_toolchain_size_diff") {
assert(defined(invoker.base_executable),
- "pw_toolchain_size_report requires a base_executable")
+ "pw_toolchain_size_diff requires a base_executable")
assert(defined(invoker.diff_executable),
- "pw_toolchain_size_report requires a diff_executable")
+ "pw_toolchain_size_diff requires a diff_executable")
_size_report_binaries = []
@@ -241,7 +464,7 @@ template("pw_toolchain_size_report") {
# Create a base and diff executable for each toolchain, adding the toolchain's
# linker script to the link flags for the executable, and add them all to a
- # list of binaries for the pw_size_report template.
+ # list of binaries for the pw_size_diff template.
foreach(_toolchain, pw_bloat_TOOLCHAINS) {
_prefix = "_${target_name}_${i}_pw_size"
@@ -290,7 +513,7 @@ template("pw_toolchain_size_report") {
_diff_label = get_label_info(":$_diff_target_name", "label_no_toolchain")
_diff_with_toolchain = "$_diff_label(${_toolchain.target})"
- # Append a pw_size_report binary scope to the list comparing the toolchain's
+ # Append a pw_size_diff binary scope to the list comparing the toolchain's
# diff and base executables.
_size_report_binaries += [
{
@@ -310,7 +533,7 @@ template("pw_toolchain_size_report") {
# TODO(frolv): Have a way of indicating that a toolchain should build docs.
if (current_toolchain == default_toolchain && _size_report_binaries != []) {
# Create the size report which runs on the binaries.
- pw_size_report(target_name) {
+ pw_size_diff(target_name) {
forward_variables_from(invoker, [ "title" ])
binaries = _size_report_binaries
}
@@ -334,7 +557,7 @@ template("pw_toolchain_size_report") {
}
}
-# A base_executable for the pw_toolchain_size_report template which contains a
+# A base_executable for the pw_toolchain_size_diff template which contains a
# main() function that loads the bloat_this_binary library and does nothing
# else.
pw_bloat_empty_base = {