blob: d9ec728d30f115d70435a4c5fb1a0129424acf32 [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
Alexei Frolovd1f98fa2019-11-08 15:41:37 -080018# Defines an action to run a Python script.
19#
20# This wraps a regular Python script action with an invocation of a script-
21# runner script which resolves GN paths to filesystem paths and locates output
22# files for binary targets.
23#
24# The interface to this template is identical to that of a regular "action"
25# which runs a Python script, except for two key differences:
26#
27# 1. Regular GN actions typically require a call to rebase_path to resolve
28# GN paths to filesystem paths. This template requires that all paths
29# remain GN paths, but are made absolute.
30#
31# This means that an "action" argument of the form:
32#
33# rebase_path("my/relative/path:optional_target", root_build_dir)
34#
35# Becomes:
36#
37# get_path_info("my/relative/path:optional_target", "abspath")
38#
39# 2. The behavior of the runner script depends on whether a provided path is a
40# regular build path or an output path (starting with "$root_out_dir").
41# If an output path is provided and the path has a target, the script
42# assumes that the target refers to a file built by Ninja and tries to
43# locate it within the output directory.
44#
Alexei Frolov917756d2019-11-12 14:34:34 -080045# Additionally, this template can accept a boolean "stamp" argument. If set to
46# true, the script runner will touch a file to indicate the success of the run.
47# This is provided so that individual Python scripts are not required to define
48# an output file if they do not have one.
49#
Alexei Frolovd1f98fa2019-11-08 15:41:37 -080050# Path resolution examples (assuming the build directory is //out):
51#
52# BEFORE AFTER
53#
54# //my_module ../my_module
55# //my_module:foo ../my_module:foo
56# //my_module/file.txt ../my_module/file.txt
57# $root_out_dir/my_module ../out/obj/my_module
58# $target_out_dir ../out/obj/my_module (in //my_module/BUILD.gn)
59# $target_out_dir/out.json ../out/obj/my_module/out.json
60# $target_out_dir:foo ../out/obj/my_module/foo.elf (toolchain-dependent)
61# $target_out_dir:foo ../out/obj/my_module/foo.exe (toolchain-dependent)
62#
Keir Mierlefa2fbe62019-12-23 11:13:02 -080063# Arguments beyond normal action() target arguments:
64#
65# capture_output (=true) If true, script output is hidden unless the script
66# fails with an error. Defaults to true.
67#
Wyatt Heplera74f7b02020-07-23 14:10:56 -070068# stamp File to touch if the script is successful. If set to
69# true, a generic file is used. If false or not set,
70# no file is touched.
Keir Mierlefa2fbe62019-12-23 11:13:02 -080071#
Alexei Frolovd1f98fa2019-11-08 15:41:37 -080072template("pw_python_script") {
Alexei Frolovbaaa2d62019-11-12 16:20:51 -080073 assert(defined(invoker.script), "pw_python_script requires a script to run")
74
Alexei Frolovd1f98fa2019-11-08 15:41:37 -080075 _script_args = [
76 # GN root directory relative to the build directory (in which the runner
77 # script is invoked).
78 "--gn-root",
Wyatt Hepler8224a642020-07-29 08:55:56 -070079 rebase_path("//"),
Alexei Frolovd1f98fa2019-11-08 15:41:37 -080080
Wyatt Hepler8224a642020-07-29 08:55:56 -070081 # Current directory, used to resolve relative paths.
82 "--current-path",
83 rebase_path("."),
84
85 "--default-toolchain=$default_toolchain",
86 "--current-toolchain=$current_toolchain",
Alexei Frolovd1f98fa2019-11-08 15:41:37 -080087 ]
88
Alexei Frolovbaaa2d62019-11-12 16:20:51 -080089 if (defined(invoker.inputs)) {
90 _inputs = invoker.inputs
91 } else {
92 _inputs = []
93 }
94
95 # List the script to run as an input so that the action is re-run when it is
96 # modified.
97 _inputs += [ invoker.script ]
98
Alexei Frolov917756d2019-11-12 14:34:34 -080099 if (defined(invoker.outputs)) {
100 _outputs = invoker.outputs
101 } else {
102 _outputs = []
103 }
104
105 # If a stamp file is requested, add it as an output of the runner script.
Wyatt Heplera74f7b02020-07-23 14:10:56 -0700106 if (defined(invoker.stamp) && invoker.stamp != false) {
107 if (invoker.stamp == true) {
108 _stamp_file = "$target_gen_dir/$target_name.pw_pystamp"
109 } else {
110 _stamp_file = invoker.stamp
111 }
112
Alexei Frolov917756d2019-11-12 14:34:34 -0800113 _outputs += [ _stamp_file ]
114 _script_args += [
115 "--touch",
Wyatt Hepler8224a642020-07-29 08:55:56 -0700116 rebase_path(_stamp_file),
Alexei Frolov917756d2019-11-12 14:34:34 -0800117 ]
118 }
119
Keir Mierlefa2fbe62019-12-23 11:13:02 -0800120 # Capture output or not.
121 # Note: capture defaults to true.
Wyatt Hepler8224a642020-07-29 08:55:56 -0700122 if (defined(invoker.capture_output)) {
Keir Mierlefa2fbe62019-12-23 11:13:02 -0800123 forward_variables_from(invoker, [ "capture_output" ])
Wyatt Hepler8224a642020-07-29 08:55:56 -0700124 } else {
125 capture_output = true
Keir Mierlefa2fbe62019-12-23 11:13:02 -0800126 }
127 if (capture_output) {
128 _script_args += [ "--capture-output" ]
129 }
130
Alexei Frolov917756d2019-11-12 14:34:34 -0800131 # "--" indicates the end of arguments to the runner script.
132 # Everything beyond this point is interpreted as the command and arguments
133 # of the Python script to run.
134 _script_args += [ "--" ]
135
Wyatt Hepler8224a642020-07-29 08:55:56 -0700136 _script_args += [ rebase_path(invoker.script) ]
137
Alexei Frolovd1f98fa2019-11-08 15:41:37 -0800138 if (defined(invoker.args)) {
139 _script_args += invoker.args
140 }
141
142 action(target_name) {
143 _ignore_vars = [
144 "script",
145 "args",
Alexei Frolovbaaa2d62019-11-12 16:20:51 -0800146 "inputs",
Alexei Frolov917756d2019-11-12 14:34:34 -0800147 "outputs",
Alexei Frolovd1f98fa2019-11-08 15:41:37 -0800148 ]
149 forward_variables_from(invoker, "*", _ignore_vars)
150
Wyatt Hepler27f69f02020-07-27 09:06:21 -0700151 script = "$dir_pw_build/py/pw_build/python_runner.py"
Alexei Frolovd1f98fa2019-11-08 15:41:37 -0800152 args = _script_args
Alexei Frolovbaaa2d62019-11-12 16:20:51 -0800153 inputs = _inputs
Alexei Frolov917756d2019-11-12 14:34:34 -0800154 outputs = _outputs
Alexei Frolovd1f98fa2019-11-08 15:41:37 -0800155 }
156}