• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1# Copyright 2020 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
15import("//build_overrides/pigweed.gni")
16
17# Defines an action that runs a Python script.
18#
19# This wraps a regular Python script GN action with an invocation of a script-
20# runner script that adds useful features. pw_python_action() uses the same
21# actions as GN's action(), with the following additions or changes:
22#
23#   module          May be used in place of the script argument to run the
24#                   provided Python module with `python -m` instead of a script.
25#                   Either script or module must be provided.
26#
27#   capture_output  If true, script output is hidden unless the script fails
28#                   with an error. Defaults to true.
29#
30#   stamp           File to touch if the script is successful. Actions that
31#                   don't create output files can use this stamp file instead of
32#                   creating their own dummy file. If true, a generic file is
33#                   used. If false or not set, no file is touched.
34#
35#   directory       The directory from which to execute the Python script. Paths
36#                   in args may need to be adjusted to be relative to this
37#                   directory.
38#
39#   environment     Environment variables to set, passed as a list of NAME=VALUE
40#                   strings.
41#
42#   args            Same as the standard action args, except special expressions
43#                   may be used to extract information not normally accessible
44#                   in GN. These include the following:
45#
46#                     <TARGET_FILE(//some/label:here)> - expands to the
47#                         output file (such as a .a or .elf) from a GN target
48#                     <TARGET_FILE_IF_EXISTS(//some/label:here)> - expands to
49#                         the output file if the target exists, or nothing
50#                     <TARGET_OBJECTS(//some/label:here)> - expands to the
51#                         object files produced by the provided GN target
52#
53#   python_deps     Dependencies on pw_python_package or related Python targets.
54#
55template("pw_python_action") {
56  _script_args = [
57    # GN root directory relative to the build directory (in which the runner
58    # script is invoked).
59    "--gn-root",
60    rebase_path("//"),
61
62    # Current directory, used to resolve relative paths.
63    "--current-path",
64    rebase_path("."),
65
66    "--default-toolchain=$default_toolchain",
67    "--current-toolchain=$current_toolchain",
68  ]
69
70  if (defined(invoker.directory)) {
71    _script_args += [
72      "--directory",
73      rebase_path(invoker.directory),
74    ]
75  }
76
77  if (defined(invoker.environment)) {
78    foreach(variable, invoker.environment) {
79      _script_args += [ "--env=$variable" ]
80    }
81  }
82
83  if (defined(invoker.inputs)) {
84    _inputs = invoker.inputs
85  } else {
86    _inputs = []
87  }
88
89  # List the script to run as an input so that the action is re-run when it is
90  # modified.
91  if (defined(invoker.script)) {
92    _inputs += [ invoker.script ]
93  }
94
95  if (defined(invoker.outputs)) {
96    _outputs = invoker.outputs
97  } else {
98    _outputs = []
99  }
100
101  # If a stamp file is requested, add it as an output of the runner script.
102  if (defined(invoker.stamp) && invoker.stamp != false) {
103    if (invoker.stamp == true) {
104      _stamp_file = "$target_gen_dir/$target_name.pw_pystamp"
105    } else {
106      _stamp_file = invoker.stamp
107    }
108
109    _outputs += [ _stamp_file ]
110    _script_args += [
111      "--touch",
112      rebase_path(_stamp_file),
113    ]
114  }
115
116  # Capture output or not (defaults to true).
117  if (!defined(invoker.capture_output) || invoker.capture_output) {
118    _script_args += [ "--capture-output" ]
119  }
120
121  if (defined(invoker.module)) {
122    _script_args += [
123      "--module",
124      invoker.module,
125    ]
126  }
127
128  # "--" indicates the end of arguments to the runner script.
129  # Everything beyond this point is interpreted as the command and arguments
130  # of the Python script to run.
131  _script_args += [ "--" ]
132
133  if (defined(invoker.script)) {
134    _script_args += [ rebase_path(invoker.script) ]
135  }
136
137  if (defined(invoker.args)) {
138    _script_args += invoker.args
139  }
140
141  if (defined(invoker._pw_action_type)) {
142    _action_type = invoker._pw_action_type
143  } else {
144    _action_type = "action"
145  }
146
147  if (defined(invoker.deps)) {
148    _deps = invoker.deps
149  } else {
150    _deps = []
151  }
152
153  if (defined(invoker.python_deps)) {
154    foreach(dep, invoker.python_deps) {
155      _deps += [ get_label_info(dep, "label_no_toolchain") + ".install(" +
156                 get_label_info(dep, "toolchain") + ")" ]
157    }
158  }
159
160  target(_action_type, target_name) {
161    _ignore_vars = [
162      "script",
163      "args",
164      "deps",
165      "inputs",
166      "outputs",
167    ]
168    forward_variables_from(invoker, "*", _ignore_vars)
169
170    script = "$dir_pw_build/py/pw_build/python_runner.py"
171    args = _script_args
172    inputs = _inputs
173    outputs = _outputs
174    deps = _deps
175  }
176}
177
178# Runs pw_python_action once per file over a set of sources.
179#
180# This template brings pw_python_action's features to action_foreach. Usage is
181# the same as pw_python_action, except that sources must be provided and source
182# expansion (e.g. "{{source}}") may be used in args and outputs.
183#
184# See the pw_python_action and action_foreach documentation for full details.
185template("pw_python_action_foreach") {
186  assert(defined(invoker.sources) && invoker.sources != [],
187         "pw_python_action_foreach requires a list of one or more sources")
188
189  pw_python_action(target_name) {
190    if (defined(invoker.stamp) && invoker.stamp != false) {
191      if (invoker.stamp == true) {
192        # Use source file names in the generated stamp file path so they are
193        # unique for each source.
194        stamp = "$target_gen_dir/{{source_file_part}}.pw_pystamp"
195      } else {
196        stamp = invoker.stamp
197      }
198    } else {
199      stamp = false
200    }
201
202    forward_variables_from(invoker, "*", [ "stamp" ])
203
204    _pw_action_type = "action_foreach"
205  }
206}
207