1# Copyright (C) 2023 The Android Open Source Project 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 15""" 16This file contains rules for defininig GBL toolchains. 17""" 18 19load( 20 "@bazel_tools//tools/cpp:cc_toolchain_config_lib.bzl", 21 "action_config", 22 "flag_group", 23 "flag_set", 24 "tool", 25 "tool_path", 26) 27load("@gbl_llvm_prebuilts//:info.bzl", "LLVM_PREBUILTS_C_INCLUDE", "gbl_llvm_tool_path") 28load("@rules_cc//cc:action_names.bzl", "ACTION_NAMES", "ALL_CPP_COMPILE_ACTION_NAMES") 29 30def _flag_set(flags): 31 """Convert a list of compile/link flags to a flag_set type.""" 32 return flag_set( 33 flag_groups = [ 34 flag_group( 35 flags = flags, 36 ), 37 ], 38 ) 39 40def _gbl_clang_cc_toolchain_config_impl(ctx): 41 """Implementation for rule _gbl_clang_cc_toolchain_config()""" 42 builtin_includes = ctx.attr.builtin_includes or [LLVM_PREBUILTS_C_INCLUDE] 43 common_compile_flagset = [ 44 _flag_set([ 45 "--target={}".format(ctx.attr.target_system_triple), 46 "-nostdinc", 47 "-no-canonical-prefixes", 48 "-Werror", 49 "-Wall", 50 ] + ["-I{}".format(inc) for inc in builtin_includes] + ctx.attr.cc_flags), 51 ] 52 return cc_common.create_cc_toolchain_config_info( 53 ctx = ctx, 54 cxx_builtin_include_directories = builtin_includes, 55 toolchain_identifier = "{}_id".format(ctx.attr.cc_toolchain_name), 56 host_system_name = "local", 57 target_system_name = ctx.attr.target_system_triple, 58 target_cpu = ctx.attr.target_cpu, 59 target_libc = "unknown", 60 compiler = "clang", 61 abi_version = "unknown", 62 abi_libc_version = "unknown", 63 action_configs = [ 64 action_config( 65 action_name = action_name, 66 enabled = True, 67 tools = [tool(path = gbl_llvm_tool_path("clang++"))], 68 flag_sets = common_compile_flagset, 69 ) 70 for action_name in ALL_CPP_COMPILE_ACTION_NAMES + 71 [ACTION_NAMES.assemble, ACTION_NAMES.preprocess_assemble] 72 ] + [ 73 action_config( 74 action_name = ACTION_NAMES.c_compile, 75 enabled = True, 76 tools = [tool(path = gbl_llvm_tool_path("clang"))], 77 flag_sets = common_compile_flagset, 78 ), 79 ] + [ 80 action_config( 81 action_name = ACTION_NAMES.cpp_link_executable, 82 enabled = True, 83 tools = [tool(path = gbl_llvm_tool_path("clang++"))], 84 flag_sets = [_flag_set(ctx.attr.ld_flags)] if ctx.attr.ld_flags else [], 85 ), 86 ], 87 tool_paths = [ 88 tool_path( 89 name = "ld", 90 path = gbl_llvm_tool_path("clang++"), 91 ), 92 tool_path( 93 name = "ar", 94 path = gbl_llvm_tool_path("llvm-ar"), 95 ), 96 tool_path( 97 name = "cpp", 98 path = gbl_llvm_tool_path("clang++"), 99 ), 100 tool_path( 101 name = "gcc", 102 path = gbl_llvm_tool_path("clang"), 103 ), 104 tool_path( 105 name = "gcov", 106 path = gbl_llvm_tool_path("llvm-cov"), 107 ), 108 tool_path( 109 name = "nm", 110 path = gbl_llvm_tool_path("llvm-nm"), 111 ), 112 tool_path( 113 name = "objdump", 114 path = gbl_llvm_tool_path("llvm-objdump"), 115 ), 116 tool_path( 117 name = "strip", 118 path = gbl_llvm_tool_path("llvm-strip"), 119 ), 120 ], 121 ) 122 123_gbl_clang_cc_toolchain_config = rule( 124 implementation = _gbl_clang_cc_toolchain_config_impl, 125 attrs = { 126 "cc_toolchain_name": attr.string(), 127 "target_cpu": attr.string(), 128 "target_system_triple": attr.string(), 129 "cc_flags": attr.string_list(), 130 "ld_flags": attr.string_list(), 131 "builtin_includes": attr.string_list(), 132 }, 133 provides = [CcToolchainConfigInfo], 134) 135 136def gbl_clang_cc_toolchain( 137 name, 138 target_cpu, 139 target_system_triple, 140 cc_flags = None, 141 ld_flags = None, 142 builtin_includes = None): 143 """Configure a clang based cc_toolchain(). 144 145 Args: 146 name (String): Name of the target. 147 target_cpu (string): Target CPU. 148 target_system_triple (string): LLVM-style target system triple. 149 cc_flags (List): clang compile flags. 150 ld_flags (List): clang link flags 151 builtin_includes (List): Override the default list of builtin include dirs. 152 """ 153 config_name = "_{}_config".format(name) 154 _gbl_clang_cc_toolchain_config( 155 name = config_name, 156 cc_toolchain_name = name, 157 target_cpu = target_cpu, 158 target_system_triple = target_system_triple, 159 cc_flags = cc_flags, 160 ld_flags = ld_flags, 161 builtin_includes = builtin_includes, 162 ) 163 164 empty_filegroup = "_empty_{}".format(name) 165 native.filegroup(name = empty_filegroup) 166 empty_filegroup_target = ":{}".format(empty_filegroup) 167 168 native.cc_toolchain( 169 name = name, 170 toolchain_identifier = name, 171 toolchain_config = ":{}".format(config_name), 172 all_files = empty_filegroup_target, 173 compiler_files = empty_filegroup_target, 174 dwp_files = empty_filegroup_target, 175 linker_files = empty_filegroup_target, 176 objcopy_files = empty_filegroup_target, 177 strip_files = empty_filegroup_target, 178 supports_param_files = 0, 179 ) 180 181def _prebuilt_binary_impl(ctx): 182 """Generate a wrapper executable type target that simply symlinks to a given executable binary. 183 184 This is for rules that only accept executable type target but not binary file directly. 185 i.e. `rust_bindgen_toolchain` 186 """ 187 out = ctx.actions.declare_file(ctx.label.name) 188 ctx.actions.symlink( 189 output = out, 190 target_file = ctx.executable.bin, 191 ) 192 return [DefaultInfo(files = depset([out]), executable = out)] 193 194prebuilt_binary = rule( 195 implementation = _prebuilt_binary_impl, 196 executable = True, 197 attrs = { 198 "bin": attr.label(allow_single_file = True, executable = True, cfg = "exec"), 199 }, 200) 201 202# A transition rule that emits the `@gbl//toolchain:rust_no_sysroot_true` setting. 203def _no_sysroot_transition_impl(_, __): 204 return {"@gbl//toolchain:rust_no_sysroot": True} 205 206_no_sysroot_transition = transition( 207 implementation = _no_sysroot_transition_impl, 208 inputs = [], 209 outputs = ["@gbl//toolchain:rust_no_sysroot"], 210) 211 212# A rule implementation that simply forwards dependencies from attribute `deps` and generates 213# symlinks to their output files. 214def _forward_and_symlink(ctx): 215 outs = [] 216 for file in ctx.files.deps: 217 # Append the label name to the file name but keep the same extension. i.e. 218 # "<file>.<extension>" -> "<file>_<label>.<extension>" 219 stem = file.basename.removesuffix(".{}".format(file.extension)) 220 out = ctx.actions.declare_file("{}_{}.{}".format(stem, ctx.label.name, file.extension)) 221 ctx.actions.symlink(output = out, target_file = file) 222 outs.append(out) 223 return [DefaultInfo(files = depset(outs))] 224 225# A rule for building rust targets with the `@gbl//toolchain:rust_no_sysroot_true` setting. 226build_with_no_rust_sysroot = rule( 227 implementation = _forward_and_symlink, 228 cfg = _no_sysroot_transition, 229 attrs = { 230 # Mandatory attribute for rules with transition. 231 "_allowlist_function_transition": attr.label( 232 default = Label("@bazel_tools//tools/allowlists/function_transition_allowlist"), 233 ), 234 "deps": attr.label_list(allow_files = True, mandatory = True), 235 }, 236) 237 238# A transition rule that emits the "--platforms=<attr.platform>" option. 239def _platform_transition_impl(_, attr): 240 return {"//command_line_option:platforms": attr.platform} 241 242_platform_transition = transition( 243 implementation = _platform_transition_impl, 244 inputs = [], 245 outputs = ["//command_line_option:platforms"], 246) 247 248build_with_platform = rule( 249 implementation = _forward_and_symlink, 250 cfg = _platform_transition, 251 attrs = { 252 # Mandatory attribute for rules with transition. 253 "_allowlist_function_transition": attr.label( 254 default = Label("@bazel_tools//tools/allowlists/function_transition_allowlist"), 255 ), 256 "platform": attr.string(mandatory = True), 257 "deps": attr.label_list(allow_files = True, mandatory = True), 258 }, 259) 260 261# This rule creates symlink for a static library in both Linux/GNU and MSVC naming styles so that 262# rust linker is able to find it when building for them. 263# 264# When flag "-Clink-arg=-l<libname>" is passed to rustc, for Linux/GNU target platforms, the linker 265# looks for library named "lib<libname>.a", for MSVC target plaforms (i.e. UEFI), the linker looks 266# for library named "<libname>.lib". When bazel builds a cc_library target, it always outputs the 267# Linux/GNU naming style and therefore fails linking when building for UEFI targets. 268def _link_static_cc_library_impl(ctx): 269 # Put an underscore so that we don't need to deal with potential "lib" prefix from user 270 # provided name. 271 libname = "_{}".format(ctx.label.name) 272 273 # Create symlink for both naming styles. 274 out_msvc_style = ctx.actions.declare_file("{}.lib".format(libname)) 275 ctx.actions.symlink(output = out_msvc_style, target_file = ctx.files.cc_library[0]) 276 out_linux_style = ctx.actions.declare_file("lib{}.a".format(libname)) 277 ctx.actions.symlink(output = out_linux_style, target_file = ctx.files.cc_library[0]) 278 279 # Construct and return a `CcInfo` for this rule that includes the library to link, so that 280 # other rust_library/cc_library can depend directly on this target. 281 library_to_link = cc_common.create_library_to_link( 282 actions = ctx.actions, 283 # Either is fine, since both yield the same linker option by Bazel. 284 static_library = out_linux_style, 285 ) 286 linking_input = cc_common.create_linker_input( 287 owner = ctx.label, 288 libraries = depset([library_to_link]), 289 # Make sure both symlinks are generated. 290 additional_inputs = depset([out_msvc_style, out_linux_style]), 291 ) 292 linking_context = cc_common.create_linking_context(linker_inputs = depset([linking_input])) 293 return [CcInfo(linking_context = linking_context)] 294 295link_static_cc_library = rule( 296 implementation = _link_static_cc_library_impl, 297 attrs = { 298 "cc_library": attr.label(), # The cc_library() target for the static library. 299 }, 300) 301