blob: 1500cc4c29052678150c3df3581d06fce82d8fc5 [file] [log] [blame]
Alexei Frolovd1f98fa2019-11-08 15:41:37 -08001# Copyright 2019 The Pigweed Authors
2#
3# Licensed under the Apache License, Version 2.0 (the "License"); you may not
4# use this file except in compliance with the License. You may obtain a copy of
5# the License at
6#
7# https://www.apache.org/licenses/LICENSE-2.0
8#
9# Unless required by applicable law or agreed to in writing, software
10# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
11# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
12# License for the specific language governing permissions and limitations under
13# the License.
14
Armando Montanezfb3d3fb2020-06-09 18:12:12 -070015# gn-format disable
16import("//build_overrides/pigweed.gni")
17
18import("$dir_pigweed/legacy_target.gni")
19
Alexei Frolovd1f98fa2019-11-08 15:41:37 -080020# Defines an action to run a Python script.
21#
22# This wraps a regular Python script action with an invocation of a script-
23# runner script which resolves GN paths to filesystem paths and locates output
24# files for binary targets.
25#
26# The interface to this template is identical to that of a regular "action"
27# which runs a Python script, except for two key differences:
28#
29# 1. Regular GN actions typically require a call to rebase_path to resolve
30# GN paths to filesystem paths. This template requires that all paths
31# remain GN paths, but are made absolute.
32#
33# This means that an "action" argument of the form:
34#
35# rebase_path("my/relative/path:optional_target", root_build_dir)
36#
37# Becomes:
38#
39# get_path_info("my/relative/path:optional_target", "abspath")
40#
41# 2. The behavior of the runner script depends on whether a provided path is a
42# regular build path or an output path (starting with "$root_out_dir").
43# If an output path is provided and the path has a target, the script
44# assumes that the target refers to a file built by Ninja and tries to
45# locate it within the output directory.
46#
Alexei Frolov917756d2019-11-12 14:34:34 -080047# Additionally, this template can accept a boolean "stamp" argument. If set to
48# true, the script runner will touch a file to indicate the success of the run.
49# This is provided so that individual Python scripts are not required to define
50# an output file if they do not have one.
51#
Alexei Frolovd1f98fa2019-11-08 15:41:37 -080052# Path resolution examples (assuming the build directory is //out):
53#
54# BEFORE AFTER
55#
56# //my_module ../my_module
57# //my_module:foo ../my_module:foo
58# //my_module/file.txt ../my_module/file.txt
59# $root_out_dir/my_module ../out/obj/my_module
60# $target_out_dir ../out/obj/my_module (in //my_module/BUILD.gn)
61# $target_out_dir/out.json ../out/obj/my_module/out.json
62# $target_out_dir:foo ../out/obj/my_module/foo.elf (toolchain-dependent)
63# $target_out_dir:foo ../out/obj/my_module/foo.exe (toolchain-dependent)
64#
Keir Mierlefa2fbe62019-12-23 11:13:02 -080065# Arguments beyond normal action() target arguments:
66#
67# capture_output (=true) If true, script output is hidden unless the script
68# fails with an error. Defaults to true.
69#
70# stamp File to touch if the script is successful. If not
71# set, no file is touched.
72#
Alexei Frolovd1f98fa2019-11-08 15:41:37 -080073template("pw_python_script") {
Alexei Frolovbaaa2d62019-11-12 16:20:51 -080074 assert(defined(invoker.script), "pw_python_script requires a script to run")
75
Alexei Frolovd1f98fa2019-11-08 15:41:37 -080076 _script_args = [
77 # GN root directory relative to the build directory (in which the runner
78 # script is invoked).
79 "--gn-root",
80 rebase_path("//", root_build_dir),
81
82 # Output directory root, used to determine whether to search for a binary.
83 "--out-dir",
84 root_out_dir,
Alexei Frolovd1f98fa2019-11-08 15:41:37 -080085 ]
86
Alexei Frolovbaaa2d62019-11-12 16:20:51 -080087 if (defined(invoker.inputs)) {
88 _inputs = invoker.inputs
89 } else {
90 _inputs = []
91 }
92
93 # List the script to run as an input so that the action is re-run when it is
94 # modified.
95 _inputs += [ invoker.script ]
96
Alexei Frolov917756d2019-11-12 14:34:34 -080097 if (defined(invoker.outputs)) {
98 _outputs = invoker.outputs
99 } else {
100 _outputs = []
101 }
102
103 # If a stamp file is requested, add it as an output of the runner script.
104 if (defined(invoker.stamp) && invoker.stamp) {
105 _stamp_file = "$target_gen_dir/$target_name.pw_pystamp"
106 _outputs += [ _stamp_file ]
107 _script_args += [
108 "--touch",
109 _stamp_file,
110 ]
111 }
112
Keir Mierlefa2fbe62019-12-23 11:13:02 -0800113 # Capture output or not.
114 # Note: capture defaults to true.
115 if (!defined(invoker.capture_output)) {
116 capture_output = true
117 } else {
118 forward_variables_from(invoker, [ "capture_output" ])
119 }
120 if (capture_output) {
121 _script_args += [ "--capture-output" ]
122 }
123
Alexei Frolov917756d2019-11-12 14:34:34 -0800124 # "--" indicates the end of arguments to the runner script.
125 # Everything beyond this point is interpreted as the command and arguments
126 # of the Python script to run.
127 _script_args += [ "--" ]
128
Alexei Frolovd1f98fa2019-11-08 15:41:37 -0800129 _script_args += [ get_path_info(invoker.script, "abspath") ]
130 if (defined(invoker.args)) {
131 _script_args += invoker.args
132 }
133
134 action(target_name) {
135 _ignore_vars = [
136 "script",
137 "args",
Alexei Frolovbaaa2d62019-11-12 16:20:51 -0800138 "inputs",
Alexei Frolov917756d2019-11-12 14:34:34 -0800139 "outputs",
Alexei Frolovd1f98fa2019-11-08 15:41:37 -0800140 ]
141 forward_variables_from(invoker, "*", _ignore_vars)
142
143 script = "$dir_pw_build/py/python_runner.py"
144 args = _script_args
Alexei Frolovbaaa2d62019-11-12 16:20:51 -0800145 inputs = _inputs
Alexei Frolov917756d2019-11-12 14:34:34 -0800146 outputs = _outputs
Alexei Frolovd1f98fa2019-11-08 15:41:37 -0800147 }
148}