| # Copyright 2019 The Bazel Authors. All rights reserved. |
| # |
| # Licensed under the Apache License, Version 2.0 (the "License"); |
| # you may not use this file except in compliance with the License. |
| # You may obtain a copy of the License at |
| # |
| # http://www.apache.org/licenses/LICENSE-2.0 |
| # |
| # Unless required by applicable law or agreed to in writing, software |
| # distributed under the License is distributed on an "AS IS" BASIS, |
| # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| # See the License for the specific language governing permissions and |
| # limitations under the License. |
| |
| """ |
| run_binary() build rule implementation. |
| |
| Runs a binary as a build action. This rule does not require Bash (unlike native.genrule()). |
| """ |
| |
| load("//lib:dicts.bzl", "dicts") |
| |
| def _impl(ctx): |
| tool_as_list = [ctx.attr.tool] |
| args = [ |
| # Expand $(location) / $(locations) in args. |
| # |
| # To keep the rule simple, do not expand Make Variables (like *_binary.args usually would). |
| # (We can add this feature later if users ask for it.) |
| # |
| # Also for simple implementation and usage, do not Bash-tokenize the arguments. Without |
| # tokenization the user can write args=["a b"] to pass (a b) as one argument, but with |
| # tokenization they would have to write args=["'a b'"] or args=["a\\ b"]. There's no |
| # documented tokenization function anyway (as of 2019-05-21 ctx.tokenize exists but is |
| # undocumented, see https://github.com/bazelbuild/bazel/issues/8389). |
| ctx.expand_location(a, tool_as_list) if "$(location" in a else a |
| for a in ctx.attr.args |
| ] |
| envs = { |
| # Expand $(location) / $(locations) in the values. |
| k: ctx.expand_location(v, tool_as_list) if "$(location" in v else v |
| for k, v in ctx.attr.env.items() |
| } |
| ctx.actions.run( |
| outputs = ctx.outputs.outs, |
| inputs = ctx.files.srcs, |
| tools = [ctx.executable.tool], |
| executable = ctx.executable.tool, |
| arguments = args, |
| mnemonic = "RunBinary", |
| use_default_shell_env = False, |
| env = dicts.add(ctx.configuration.default_shell_env, envs), |
| ) |
| return DefaultInfo( |
| files = depset(ctx.outputs.outs), |
| runfiles = ctx.runfiles(files = ctx.outputs.outs), |
| ) |
| |
| run_binary = rule( |
| implementation = _impl, |
| doc = "Runs a binary as a build action.\n\nThis rule does not require Bash (unlike" + |
| " `native.genrule`).", |
| attrs = { |
| "tool": attr.label( |
| doc = "The tool to run in the action.\n\nMust be the label of a *_binary rule," + |
| " of a rule that generates an executable file, or of a file that can be" + |
| " executed as a subprocess (e.g. an .exe or .bat file on Windows or a binary" + |
| " with executable permission on Linux). This label is available for" + |
| " `$(location)` expansion in `args` and `env`.", |
| executable = True, |
| allow_files = True, |
| mandatory = True, |
| cfg = "exec", |
| ), |
| "env": attr.string_dict( |
| doc = "Environment variables of the action.\n\nSubject to " + |
| " [`$(location)`](https://bazel.build/reference/be/make-variables#predefined_label_variables)" + |
| " expansion.", |
| ), |
| "srcs": attr.label_list( |
| allow_files = True, |
| doc = "Additional inputs of the action.\n\nThese labels are available for" + |
| " `$(location)` expansion in `args` and `env`.", |
| ), |
| "outs": attr.output_list( |
| mandatory = True, |
| doc = "Output files generated by the action.\n\nThese labels are available for" + |
| " `$(location)` expansion in `args` and `env`.", |
| ), |
| "args": attr.string_list( |
| doc = "Command line arguments of the binary.\n\nSubject to" + |
| " [`$(location)`](https://bazel.build/reference/be/make-variables#predefined_label_variables)" + |
| " expansion.", |
| ), |
| }, |
| ) |