| # 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 = [ |
| "${_doc_rst_output}.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", |
| ] |
| } |