aboutsummaryrefslogtreecommitdiff
path: root/rules/run_binary.bzl
blob: 7701fa0dea1c0fde017523cf8a3c967ca6791805 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
# 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.",
        ),
    },
)