• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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("@bazel_skylib//rules/directory:providers.bzl", "DirectoryInfo")
17load("//cc/toolchains/impl:collect.bzl", "collect_data", "collect_provider")
18load(
19    ":cc_toolchain_info.bzl",
20    "ToolCapabilityInfo",
21    "ToolInfo",
22)
23
24def _cc_tool_impl(ctx):
25    exe_info = ctx.attr.src[DefaultInfo]
26    if exe_info.files_to_run != None and exe_info.files_to_run.executable != None:
27        exe = exe_info.files_to_run.executable
28    elif len(exe_info.files.to_list()) == 1:
29        exe = exe_info.files.to_list()[0]
30    else:
31        fail("Expected cc_tool's src attribute to be either an executable or a single file")
32
33    runfiles = collect_data(ctx, ctx.attr.data + [ctx.attr.src] + ctx.attr.allowlist_include_directories)
34    tool = ToolInfo(
35        label = ctx.label,
36        exe = exe,
37        runfiles = runfiles,
38        execution_requirements = tuple(ctx.attr.tags),
39        allowlist_include_directories = depset(
40            direct = [d[DirectoryInfo] for d in ctx.attr.allowlist_include_directories],
41        ),
42        capabilities = tuple(collect_provider(ctx.attr.capabilities, ToolCapabilityInfo)),
43    )
44
45    link = ctx.actions.declare_file(ctx.label.name)
46    ctx.actions.symlink(
47        output = link,
48        target_file = exe,
49        is_executable = True,
50    )
51    return [
52        tool,
53        # This isn't required, but now we can do "bazel run <tool>", which can
54        # be very helpful when debugging toolchains.
55        DefaultInfo(
56            files = depset([link]),
57            runfiles = runfiles,
58            executable = link,
59        ),
60    ]
61
62cc_tool = rule(
63    implementation = _cc_tool_impl,
64    # @unsorted-dict-items
65    attrs = {
66        "src": attr.label(
67            allow_files = True,
68            cfg = "exec",
69            doc = """The underlying binary that this tool represents.
70
71Usually just a single prebuilt (eg. @toolchain//:bin/clang), but may be any
72executable label.
73""",
74        ),
75        "data": attr.label_list(
76            allow_files = True,
77            doc = """Additional files that are required for this tool to run.
78
79Frequently, clang and gcc require additional files to execute as they often shell out to
80other binaries (e.g. `cc1`).
81""",
82        ),
83        "allowlist_include_directories": attr.label_list(
84            providers = [DirectoryInfo],
85            doc = """Include paths implied by using this tool.
86
87Compilers may include a set of built-in headers that are implicitly available
88unless flags like `-nostdinc` are provided. Bazel checks that all included
89headers are properly provided by a dependency or allowlisted through this
90mechanism.
91
92As a rule of thumb, only use this if Bazel is complaining about absolute paths in your
93toolchain and you've ensured that the toolchain is compiling with the `-no-canonical-prefixes`
94and/or `-fno-canonical-system-headers` arguments.
95
96This can help work around errors like:
97`the source file 'main.c' includes the following non-builtin files with absolute paths
98(if these are builtin files, make sure these paths are in your toolchain)`.
99""",
100        ),
101        "capabilities": attr.label_list(
102            providers = [ToolCapabilityInfo],
103            doc = """Declares that a tool is capable of doing something.
104
105For example, `@rules_cc//cc/toolchains/capabilities:supports_pic`.
106""",
107        ),
108    },
109    provides = [ToolInfo],
110    doc = """Declares a tool for use by toolchain actions.
111
112`cc_tool` rules are used in a `cc_tool_map` rule to ensure all files and
113metadata required to run a tool are available when constructing a `cc_toolchain`.
114
115In general, include all files that are always required to run a tool (e.g. libexec/** and
116cross-referenced tools in bin/*) in the [data](#cc_tool-data) attribute. If some files are only
117required when certain flags are passed to the tool, consider using a `cc_args` rule to
118bind the files to the flags that require them. This reduces the overhead required to properly
119enumerate a sandbox with all the files required to run a tool, and ensures that there isn't
120unintentional leakage across configurations and actions.
121
122Example:
123```
124load("//cc/toolchains:tool.bzl", "cc_tool")
125
126cc_tool(
127    name = "clang_tool",
128    executable = "@llvm_toolchain//:bin/clang",
129    # Suppose clang needs libc to run.
130    data = ["@llvm_toolchain//:lib/x86_64-linux-gnu/libc.so.6"]
131    tags = ["requires-network"],
132    capabilities = ["//cc/toolchains/capabilities:supports_pic"],
133)
134```
135""",
136    executable = True,
137)
138