# Copyright 2020 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") # Defines an action that runs a Python script. # # This wraps a regular Python script GN action with an invocation of a script- # runner script that adds useful features. pw_python_action() uses the same # actions as GN's action(), with the following additions or changes: # # module May be used in place of the script argument to run the # provided Python module with `python -m` instead of a script. # Either script or module must be provided. # # capture_output If true, script output is hidden unless the script fails # with an error. Defaults to true. # # stamp File to touch if the script is successful. Actions that # don't create output files can use this stamp file instead of # creating their own placeholder file. If true, a generic file # is used. If false or not set, no file is touched. # # environment Environment variables to set, passed as a list of NAME=VALUE # strings. # # args Same as the standard action args, except special expressions # may be used to extract information not normally accessible # in GN. These include the following: # # - expands to the # output file (such as a .a or .elf) from a GN target # - expands to # the output file if the target exists, or nothing # - expands to the # object files produced by the provided GN target # # python_deps Dependencies on pw_python_package or related Python targets. # template("pw_python_action") { assert(defined(invoker.script) != defined(invoker.module), "pw_python_action requires either 'script' or 'module'") _script_args = [ # GN root directory relative to the build directory (in which the runner # script is invoked). "--gn-root", rebase_path("//", root_build_dir), # Current directory, used to resolve relative paths. "--current-path", rebase_path(".", root_build_dir), "--default-toolchain=$default_toolchain", "--current-toolchain=$current_toolchain", ] if (defined(invoker.environment)) { foreach(variable, invoker.environment) { _script_args += [ "--env=$variable" ] } } if (defined(invoker.inputs)) { _inputs = invoker.inputs } else { _inputs = [] } # List the script to run as an input so that the action is re-run when it is # modified. if (defined(invoker.script)) { _inputs += [ invoker.script ] } if (defined(invoker.outputs)) { _outputs = invoker.outputs } else { _outputs = [] } # If a stamp file is requested, add it as an output of the runner script. if (defined(invoker.stamp) && invoker.stamp != false) { if (invoker.stamp == true) { _stamp_file = "$target_gen_dir/$target_name.pw_pystamp" } else { _stamp_file = invoker.stamp } _outputs += [ _stamp_file ] _script_args += [ "--touch", rebase_path(_stamp_file, root_build_dir), ] } # Capture output or not (defaults to true). if (!defined(invoker.capture_output) || invoker.capture_output) { _script_args += [ "--capture-output" ] } if (defined(invoker.module)) { _script_args += [ "--module", invoker.module, ] } # "--" indicates the end of arguments to the runner script. # Everything beyond this point is interpreted as the command and arguments # of the Python script to run. _script_args += [ "--" ] if (defined(invoker.script)) { _script_args += [ rebase_path(invoker.script, root_build_dir) ] } if (defined(invoker.args)) { _script_args += invoker.args } if (defined(invoker._pw_action_type)) { _action_type = invoker._pw_action_type } else { _action_type = "action" } if (defined(invoker.deps)) { _deps = invoker.deps } else { _deps = [] } if (defined(invoker.python_deps)) { foreach(dep, invoker.python_deps) { _deps += [ get_label_info(dep, "label_no_toolchain") + ".install(" + get_label_info(dep, "toolchain") + ")" ] } # Add the base target as a dep so the action reruns when any source files # change, even if the package does not have to be reinstalled. _deps += invoker.python_deps } target(_action_type, target_name) { _ignore_vars = [ "script", "args", "deps", "inputs", "outputs", ] forward_variables_from(invoker, "*", _ignore_vars) script = "$dir_pw_build/py/pw_build/python_runner.py" args = _script_args inputs = _inputs outputs = _outputs deps = _deps } } # Runs pw_python_action once per file over a set of sources. # # This template brings pw_python_action's features to action_foreach. Usage is # the same as pw_python_action, except that sources must be provided and source # expansion (e.g. "{{source}}") may be used in args and outputs. # # See the pw_python_action and action_foreach documentation for full details. template("pw_python_action_foreach") { assert(defined(invoker.sources) && invoker.sources != [], "pw_python_action_foreach requires a list of one or more sources") pw_python_action(target_name) { if (defined(invoker.stamp) && invoker.stamp != false) { if (invoker.stamp == true) { # Use source file names in the generated stamp file path so they are # unique for each source. stamp = "$target_gen_dir/{{source_file_part}}.pw_pystamp" } else { stamp = invoker.stamp } } else { stamp = false } forward_variables_from(invoker, "*", [ "stamp" ]) _pw_action_type = "action_foreach" } }