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