| # Copyright 2019 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 | |
| # the License at | |
| # | |
| # https://www.apache.org/licenses/LICENSE-2.0 | |
| # | |
| # Unless required by applicable law or agreed to in writing, software | |
| # distributed under the License is distributed on an "AS IS" BASIS, WITHOUT | |
| # WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the | |
| # License for the specific language governing permissions and limitations under | |
| # the License. | |
| import("//build_overrides/pigweed.gni") | |
| import("$dir_pw_build/python_action.gni") | |
| declare_args() { | |
| # Path to the Bloaty configuration file that defines the memory layout and | |
| # capacities for the target binaries. | |
| pw_bloat_BLOATY_CONFIG = "" | |
| # List of toolchains to use in pw_toolchain_size_report templates. | |
| # | |
| # Each entry is a scope containing the following variables: | |
| # | |
| # name: Human-readable toolchain name. | |
| # target: GN target that defines the toolchain. | |
| # linker_script: Optional path to a linker script file to build for the | |
| # toolchain's target. | |
| # 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. | |
| pw_bloat_TOOLCHAINS = [] | |
| # Controls whether to display size reports in the build output. | |
| pw_bloat_SHOW_SIZE_REPORTS = false | |
| } | |
| # 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. | |
| # 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. | |
| # | |
| # Example: | |
| # pw_size_report("foo_bloat") { | |
| # base = ":foo_base" | |
| # binaries = [ | |
| # { | |
| # target = ":foo_static" | |
| # label = "Static" | |
| # }, | |
| # { | |
| # target = ":foo_dynamic" | |
| # label = "Dynamic" | |
| # }, | |
| # ] | |
| # title = "static vs. dynamic foo" | |
| # } | |
| # | |
| template("pw_size_report") { | |
| if (pw_bloat_BLOATY_CONFIG != "") { | |
| if (defined(invoker.base)) { | |
| _global_base = invoker.base | |
| _all_target_dependencies = [ _global_base ] | |
| } else { | |
| _all_target_dependencies = [] | |
| } | |
| if (defined(invoker.title)) { | |
| _title = invoker.title | |
| } else { | |
| _title = target_name | |
| } | |
| # This template creates an action which invokes a Python script to run a | |
| # size report on each of the provided targets. Each of the targets is listed | |
| # as a dependency of the action so that the report gets updated when | |
| # 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 = [] | |
| _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 | |
| _all_target_dependencies += [ _binary_base ] | |
| } else if (defined(_global_base)) { | |
| _binary_base = _global_base | |
| } else { | |
| assert(false, "pw_size_report requires a 'base' file") | |
| } | |
| # Allow each binary to override the global bloaty config. | |
| if (defined(binary.bloaty_config)) { | |
| _bloaty_configs += [ binary.bloaty_config ] | |
| } else { | |
| _bloaty_configs += [ pw_bloat_BLOATY_CONFIG ] | |
| } | |
| _binary_path += ";" + "<TARGET_FILE($_binary_base)>" | |
| _binary_paths += [ _binary_path ] | |
| _binary_labels += [ binary.label ] | |
| } | |
| _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), | |
| ] | |
| 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, | |
| ] | |
| } | |
| _doc_rst_output = "$target_gen_dir/${target_name}" | |
| 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 = _bloaty_configs | |
| outputs = [ | |
| "$target_gen_dir/${target_name}.txt", | |
| _doc_rst_output, | |
| ] | |
| deps = _all_target_dependencies | |
| args = _bloat_script_args + _binary_paths | |
| # 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) { | |
| } | |
| } | |
| } | |
| # Creates a report card comparing the sizes of the same binary compiled with | |
| # different toolchains. The toolchains to use are listed in the build variable | |
| # pw_bloat_TOOLCHAINS. | |
| # | |
| # Args: | |
| # base_executable: Scope containing a list of variables defining an executable | |
| # target for the size report base. | |
| # diff_executable: Scope containing a list of variables defining an executable | |
| # target for the size report comparison. | |
| # | |
| # Outputs: | |
| # $target_gen_dir/$target_name.txt | |
| # $target_gen_dir/$target_name.rst | |
| # | |
| # Example: | |
| # | |
| # pw_toolchain_size_report("my_size_report") { | |
| # base_executable = { | |
| # sources = [ "base.cc" ] | |
| # } | |
| # | |
| # diff_executable = { | |
| # sources = [ "base_with_libfoo.cc" ] | |
| # deps = [ ":libfoo" ] | |
| # } | |
| # } | |
| # | |
| template("pw_toolchain_size_report") { | |
| assert(defined(invoker.base_executable), | |
| "pw_toolchain_size_report requires a base_executable") | |
| assert(defined(invoker.diff_executable), | |
| "pw_toolchain_size_report requires a diff_executable") | |
| _size_report_binaries = [] | |
| # Multiple build targets are created for each toolchain, which all need unique | |
| # target names, so throw a counter in there. | |
| i = 0 | |
| # 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. | |
| foreach(_toolchain, pw_bloat_TOOLCHAINS) { | |
| _prefix = "_${target_name}_${i}_pw_size" | |
| # Create a config which adds the toolchain's linker script as a linker flag | |
| # if the toolchain provides one. | |
| _linker_script_target_name = "${_prefix}_linker_script" | |
| config(_linker_script_target_name) { | |
| if (defined(_toolchain.linker_script)) { | |
| ldflags = | |
| [ "-T" + rebase_path(_toolchain.linker_script, root_build_dir) ] | |
| inputs = [ _toolchain.linker_script ] | |
| } else { | |
| ldflags = [] | |
| } | |
| } | |
| # Create a group which forces the linker script config its dependents. | |
| _linker_group_target_name = "${_prefix}_linker_group" | |
| group(_linker_group_target_name) { | |
| public_configs = [ ":$_linker_script_target_name" ] | |
| } | |
| # Define the size report base executable with the toolchain's linker script. | |
| _base_target_name = "${_prefix}_base" | |
| executable(_base_target_name) { | |
| forward_variables_from(invoker.base_executable, "*") | |
| if (!defined(deps)) { | |
| deps = [] | |
| } | |
| deps += [ ":$_linker_group_target_name" ] | |
| } | |
| # Define the size report diff executable with the toolchain's linker script. | |
| _diff_target_name = "${_prefix}_diff" | |
| executable(_diff_target_name) { | |
| forward_variables_from(invoker.diff_executable, "*") | |
| if (!defined(deps)) { | |
| deps = [] | |
| } | |
| deps += [ ":$_linker_group_target_name" ] | |
| } | |
| # Force compilation with the toolchain. | |
| _base_label = get_label_info(":$_base_target_name", "label_no_toolchain") | |
| _base_with_toolchain = "$_base_label(${_toolchain.target})" | |
| _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 | |
| # diff and base executables. | |
| _size_report_binaries += [ | |
| { | |
| base = _base_with_toolchain | |
| target = _diff_with_toolchain | |
| label = _toolchain.name | |
| if (defined(_toolchain.bloaty_config)) { | |
| bloaty_config = _toolchain.bloaty_config | |
| } | |
| }, | |
| ] | |
| i += 1 | |
| } | |
| # 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) { | |
| forward_variables_from(invoker, [ "title" ]) | |
| binaries = _size_report_binaries | |
| } | |
| } else { | |
| # If no toolchains are listed in pw_bloat_TOOLCHAINS, prevent GN from | |
| # complaining about unused variables and run a script that outputs a ReST | |
| # warning to the size report file. | |
| not_needed("*") | |
| not_needed(invoker, "*") | |
| _doc_rst_output = "$target_gen_dir/$target_name" | |
| 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_toolchains.py" | |
| python_deps = [ "$dir_pw_bloat/py" ] | |
| args = [ rebase_path(_doc_rst_output, root_build_dir) ] | |
| outputs = [ _doc_rst_output ] | |
| } | |
| } | |
| } | |
| # A base_executable for the pw_toolchain_size_report template which contains a | |
| # main() function that loads the bloat_this_binary library and does nothing | |
| # else. | |
| pw_bloat_empty_base = { | |
| deps = [ | |
| "$dir_pw_bloat:base_main", | |
| "$dir_pw_bloat:bloat_this_binary", | |
| ] | |
| } |