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