| # 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. |
| |
| # Defines an action to run a Python script. |
| # |
| # This wraps a regular Python script action with an invocation of a script- |
| # runner script which resolves GN paths to filesystem paths and locates output |
| # files for binary targets. |
| # |
| # The interface to this template is identical to that of a regular "action" |
| # which runs a Python script, except for two key differences: |
| # |
| # 1. Regular GN actions typically require a call to rebase_path to resolve |
| # GN paths to filesystem paths. This template requires that all paths |
| # remain GN paths, but are made absolute. |
| # |
| # This means that an "action" argument of the form: |
| # |
| # rebase_path("my/relative/path:optional_target", root_build_dir) |
| # |
| # Becomes: |
| # |
| # get_path_info("my/relative/path:optional_target", "abspath") |
| # |
| # 2. The behavior of the runner script depends on whether a provided path is a |
| # regular build path or an output path (starting with "$root_out_dir"). |
| # If an output path is provided and the path has a target, the script |
| # assumes that the target refers to a file built by Ninja and tries to |
| # locate it within the output directory. |
| # |
| # Additionally, this template can accept a boolean "stamp" argument. If set to |
| # true, the script runner will touch a file to indicate the success of the run. |
| # This is provided so that individual Python scripts are not required to define |
| # an output file if they do not have one. |
| # |
| # Path resolution examples (assuming the build directory is //out): |
| # |
| # BEFORE AFTER |
| # |
| # //my_module ../my_module |
| # //my_module:foo ../my_module:foo |
| # //my_module/file.txt ../my_module/file.txt |
| # $root_out_dir/my_module ../out/obj/my_module |
| # $target_out_dir ../out/obj/my_module (in //my_module/BUILD.gn) |
| # $target_out_dir/out.json ../out/obj/my_module/out.json |
| # $target_out_dir:foo ../out/obj/my_module/foo.elf (toolchain-dependent) |
| # $target_out_dir:foo ../out/obj/my_module/foo.exe (toolchain-dependent) |
| # |
| # Arguments beyond normal action() target arguments: |
| # |
| # capture_output (=true) 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. If not |
| # set, no file is touched. |
| # |
| template("pw_python_script") { |
| assert(defined(invoker.script), "pw_python_script requires a script to run") |
| |
| _script_args = [ |
| # GN root directory relative to the build directory (in which the runner |
| # script is invoked). |
| "--gn-root", |
| rebase_path("//", root_build_dir), |
| |
| # Output directory root, used to determine whether to search for a binary. |
| "--out-dir", |
| root_out_dir, |
| ] |
| |
| 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. |
| _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) { |
| _stamp_file = "$target_gen_dir/$target_name.pw_pystamp" |
| _outputs += [ _stamp_file ] |
| _script_args += [ |
| "--touch", |
| _stamp_file, |
| ] |
| } |
| |
| # Capture output or not. |
| # Note: capture defaults to true. |
| if (!defined(invoker.capture_output)) { |
| capture_output = true |
| } else { |
| forward_variables_from(invoker, [ "capture_output" ]) |
| } |
| if (capture_output) { |
| _script_args += [ "--capture-output" ] |
| } |
| |
| # "--" 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 += [ "--" ] |
| |
| _script_args += [ get_path_info(invoker.script, "abspath") ] |
| if (defined(invoker.args)) { |
| _script_args += invoker.args |
| } |
| |
| action(target_name) { |
| _ignore_vars = [ |
| "script", |
| "args", |
| "inputs", |
| "outputs", |
| ] |
| forward_variables_from(invoker, "*", _ignore_vars) |
| |
| script = "$dir_pw_build/py/python_runner.py" |
| args = _script_args |
| inputs = _inputs |
| outputs = _outputs |
| } |
| } |