xref: /aosp_15_r20/external/bazelbuild-rules_cc/cc/toolchains/tool.bzl (revision eed53cd41c5909d05eedc7ad9720bb158fd93452)
1# Copyright 2023 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"""Implementation of cc_tool"""
15
16load("//cc/toolchains/impl:collect.bzl", "collect_data", "collect_provider")
17load(
18    ":cc_toolchain_info.bzl",
19    "FeatureConstraintInfo",
20    "ToolInfo",
21)
22
23def _cc_tool_impl(ctx):
24    exe_info = ctx.attr.src[DefaultInfo]
25    if exe_info.files_to_run != None and exe_info.files_to_run.executable != None:
26        exe = exe_info.files_to_run.executable
27    elif len(exe_info.files.to_list()) == 1:
28        exe = exe_info.files.to_list()[0]
29    else:
30        fail("Expected cc_tool's src attribute to be either an executable or a single file")
31
32    runfiles = collect_data(ctx, ctx.attr.data + [ctx.attr.src])
33    tool = ToolInfo(
34        label = ctx.label,
35        exe = exe,
36        runfiles = runfiles,
37        requires_any_of = tuple(collect_provider(
38            ctx.attr.requires_any_of,
39            FeatureConstraintInfo,
40        )),
41        execution_requirements = tuple(ctx.attr.execution_requirements),
42    )
43
44    link = ctx.actions.declare_file(ctx.label.name)
45    ctx.actions.symlink(
46        output = link,
47        target_file = exe,
48        is_executable = True,
49    )
50    return [
51        tool,
52        # This isn't required, but now we can do "bazel run <tool>", which can
53        # be very helpful when debugging toolchains.
54        DefaultInfo(
55            files = depset([link]),
56            runfiles = runfiles,
57            executable = link,
58        ),
59    ]
60
61cc_tool = rule(
62    implementation = _cc_tool_impl,
63    # @unsorted-dict-items
64    attrs = {
65        "src": attr.label(
66            allow_files = True,
67            cfg = "exec",
68            doc = """The underlying binary that this tool represents.
69
70Usually just a single prebuilt (eg. @sysroot//:bin/clang), but may be any
71executable label.
72""",
73        ),
74        "data": attr.label_list(
75            allow_files = True,
76            doc = "Additional files that are required for this tool to run.",
77        ),
78        "execution_requirements": attr.string_list(
79            doc = "A list of strings that provide hints for execution environment compatibility (e.g. `requires-network`).",
80        ),
81        "requires_any_of": attr.label_list(
82            providers = [FeatureConstraintInfo],
83            doc = """This will be enabled when any of the constraints are met.
84
85If omitted, this tool will be enabled unconditionally.
86""",
87        ),
88    },
89    provides = [ToolInfo],
90    doc = """Declares a tool that can be bound to action configs.
91
92A tool is a binary with extra metadata for the action config rule to consume
93(eg. execution_requirements).
94
95Example:
96```
97cc_tool(
98    name = "clang_tool",
99    executable = "@llvm_toolchain//:bin/clang",
100    # Suppose clang needs libc to run.
101    data = ["@llvm_toolchain//:lib/x86_64-linux-gnu/libc.so.6"]
102)
103```
104""",
105    executable = True,
106)
107