1# Copyright 2019 The Bazel Authors. All rights reserved. 2# 3# Licensed under the Apache License, Version 2.0 (the "License"); 4# you may not use this file except in compliance with the License. 5# You may obtain a copy of the License at 6# 7# http://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, 11# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12# See the License for the specific language governing permissions and 13# limitations under the License. 14 15""" 16run_binary() build rule implementation. 17 18Runs a binary as a build action. This rule does not require Bash (unlike native.genrule()). 19""" 20 21load("//lib:dicts.bzl", "dicts") 22 23def _impl(ctx): 24 tool_as_list = [ctx.attr.tool] 25 tool_inputs, tool_input_mfs = ctx.resolve_tools(tools = tool_as_list) 26 args = [ 27 # Expand $(location) / $(locations) in args. 28 # 29 # To keep the rule simple, do not expand Make Variables (like *_binary.args usually would). 30 # (We can add this feature later if users ask for it.) 31 # 32 # Also for simple implementation and usage, do not Bash-tokenize the arguments. Without 33 # tokenization the user can write args=["a b"] to pass (a b) as one argument, but with 34 # tokenization they would have to write args=["'a b'"] or args=["a\\ b"]. There's no 35 # documented tokenization function anyway (as of 2019-05-21 ctx.tokenize exists but is 36 # undocumented, see https://github.com/bazelbuild/bazel/issues/8389). 37 ctx.expand_location(a, tool_as_list) if "$(location" in a else a 38 for a in ctx.attr.args 39 ] 40 envs = { 41 # Expand $(location) / $(locations) in the values. 42 k: ctx.expand_location(v, tool_as_list) if "$(location" in v else v 43 for k, v in ctx.attr.env.items() 44 } 45 ctx.actions.run( 46 outputs = ctx.outputs.outs, 47 inputs = ctx.files.srcs, 48 tools = tool_inputs, 49 executable = ctx.executable.tool, 50 arguments = args, 51 mnemonic = "RunBinary", 52 use_default_shell_env = False, 53 env = dicts.add(ctx.configuration.default_shell_env, envs), 54 input_manifests = tool_input_mfs, 55 ) 56 return DefaultInfo( 57 files = depset(ctx.outputs.outs), 58 runfiles = ctx.runfiles(files = ctx.outputs.outs), 59 ) 60 61run_binary = rule( 62 implementation = _impl, 63 doc = "Runs a binary as a build action.<br/><br/>This rule does not require Bash (unlike" + 64 " <code>native.genrule</code>).", 65 attrs = { 66 "tool": attr.label( 67 doc = "The tool to run in the action.<br/><br/>Must be the label of a *_binary rule," + 68 " of a rule that generates an executable file, or of a file that can be" + 69 " executed as a subprocess (e.g. an .exe or .bat file on Windows or a binary" + 70 " with executable permission on Linux). This label is available for" + 71 " <code>$(location)</code> expansion in <code>args</code> and <code>env</code>.", 72 executable = True, 73 allow_files = True, 74 mandatory = True, 75 cfg = "host", 76 ), 77 "env": attr.string_dict( 78 doc = "Environment variables of the action.<br/><br/>Subject to " + 79 " <code><a href=\"https://docs.bazel.build/versions/master/be/make-variables.html#location\">$(location)</a></code>" + 80 " expansion.", 81 ), 82 "srcs": attr.label_list( 83 allow_files = True, 84 doc = "Additional inputs of the action.<br/><br/>These labels are available for" + 85 " <code>$(location)</code> expansion in <code>args</code> and <code>env</code>.", 86 ), 87 "outs": attr.output_list( 88 mandatory = True, 89 doc = "Output files generated by the action.<br/><br/>These labels are available for" + 90 " <code>$(location)</code> expansion in <code>args</code> and <code>env</code>.", 91 ), 92 "args": attr.string_list( 93 doc = "Command line arguments of the binary.<br/><br/>Subject to" + 94 "<code><a href=\"https://docs.bazel.build/versions/master/be/make-variables.html#location\">$(location)</a></code>" + 95 " expansion.", 96 ), 97 }, 98) 99