xref: /aosp_15_r20/external/pigweed/pw_build/exec.gni (revision 61c4878ac05f98d0ceed94b57d316916de578985)
1# 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
15import("python_action.gni")
16
17# Runs a program which isn't in Python.
18#
19# This is provided to avoid having to write a new Python wrapper script every
20# time a program needs to be run from GN.
21#
22# Args:
23#  program: The program to run. Can be a full path or just a name (in which case
24#    $PATH is searched).
25#
26#  args: Optional list of arguments to the program.
27#
28#  depfile: Optional depfile of the underlying target.
29#
30#  deps: Dependencies for this target.
31#
32#  public_deps: Public dependencies for this target. In addition to outputs from
33#    this target, outputs generated by public dependencies can be used as inputs
34#    from targets that depend on this one. This is not the case for private
35#    deps.
36#
37#  inputs: Optional list of build inputs to the program.
38#
39#  outputs: Optional list of artifacts produced by the program's execution.
40#
41#  env: Optional list of key-value pairs defining environment variables for
42#    the program.
43#
44#  env_file: Optional path to a file containing a list of newline-separated
45#    key-value pairs defining environment variables for the program.
46#
47#  args_file: Optional path to a file containing additional positional arguments
48#    to the program. Each line of the file is appended to the invocation. Useful
49#    for specifying arguments from GN metadata.
50#
51#  skip_empty_args: If args_file is provided, boolean indicating whether to skip
52#    running the program if the file is empty. Used to avoid running commands
53#    which error when called without arguments.
54#
55#  capture_output: If true, output from the program is hidden unless the program
56#    exits with an error. Defaults to true.
57#
58#  working_directory: The working directory to execute the subprocess with. If
59#    not specified it will not be set and the subprocess will have whatever the
60#    parent current working directory is.
61#
62#  venv: Python virtualenv to pass along to the underlying pw_python_action.
63#
64#  visibility: GN visibility to apply to the underlying target.
65#
66# Example:
67#
68#   pw_exec("hello_world") {
69#     program = "/bin/sh"
70#     args = [
71#       "-c",
72#       "echo hello \$WORLD",
73#     ]
74#     env = [
75#       "WORLD=world",
76#     ]
77#   }
78#
79template("pw_exec") {
80  assert(defined(invoker.program), "pw_exec requires a program to run")
81
82  _script_args = [
83    "--target",
84    target_name,
85  ]
86
87  if (defined(invoker.env_file)) {
88    _script_args += [
89      "--env-file",
90      rebase_path(invoker.env_file, root_build_dir),
91    ]
92  }
93
94  if (defined(invoker.args_file)) {
95    _script_args += [
96      "--args-file",
97      rebase_path(invoker.args_file, root_build_dir),
98    ]
99
100    if (defined(invoker.skip_empty_args) && invoker.skip_empty_args) {
101      _script_args += [ "--skip-empty-args" ]
102    }
103  }
104
105  if (defined(invoker.env)) {
106    foreach(_env, invoker.env) {
107      _script_args += [
108        "--env",
109        _env,
110      ]
111    }
112  }
113
114  if (!defined(invoker.capture_output) || invoker.capture_output) {
115    _script_args += [ "--capture-output" ]
116    _capture_output = true
117  } else {
118    _capture_output = false
119  }
120
121  if (defined(invoker.working_directory)) {
122    _script_args += [
123      "--working-directory",
124      invoker.working_directory,
125    ]
126  }
127
128  _script_args += [
129    "--",
130    invoker.program,
131  ]
132  if (defined(invoker.args)) {
133    _script_args += invoker.args
134  }
135
136  pw_python_action(target_name) {
137    script = "$dir_pw_build/py/pw_build/exec.py"
138    args = _script_args
139    capture_output = _capture_output
140
141    forward_variables_from(invoker,
142                           [
143                             "cflags",
144                             "cflags_c",
145                             "configs",
146                             "defines",
147                             "depfile",
148                             "deps",
149                             "inputs",
150                             "pool",
151                             "public_configs",
152                             "public_deps",
153                             "venv",
154                             "visibility",
155                           ])
156
157    if (!defined(inputs)) {
158      inputs = []
159    }
160    if (defined(invoker.env_file)) {
161      inputs += [ invoker.env_file ]
162    }
163
164    if (defined(invoker.outputs)) {
165      outputs = invoker.outputs
166    } else {
167      stamp = true
168    }
169  }
170}
171