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