1*d4726bddSHONG Yifan# Copyright 2019 The Bazel Authors. All rights reserved. 2*d4726bddSHONG Yifan# 3*d4726bddSHONG Yifan# Licensed under the Apache License, Version 2.0 (the "License"); 4*d4726bddSHONG Yifan# you may not use this file except in compliance with the License. 5*d4726bddSHONG Yifan# You may obtain a copy of the License at 6*d4726bddSHONG Yifan# 7*d4726bddSHONG Yifan# http://www.apache.org/licenses/LICENSE-2.0 8*d4726bddSHONG Yifan# 9*d4726bddSHONG Yifan# Unless required by applicable law or agreed to in writing, software 10*d4726bddSHONG Yifan# distributed under the License is distributed on an "AS IS" BASIS, 11*d4726bddSHONG Yifan# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12*d4726bddSHONG Yifan# See the License for the specific language governing permissions and 13*d4726bddSHONG Yifan# limitations under the License. 14*d4726bddSHONG Yifan 15*d4726bddSHONG Yifan"""Rust Bindgen rules""" 16*d4726bddSHONG Yifan 17*d4726bddSHONG Yifanload( 18*d4726bddSHONG Yifan "@bazel_tools//tools/build_defs/cc:action_names.bzl", 19*d4726bddSHONG Yifan "CPP_COMPILE_ACTION_NAME", 20*d4726bddSHONG Yifan) 21*d4726bddSHONG Yifanload("@rules_cc//cc:defs.bzl", "CcInfo", "cc_library") 22*d4726bddSHONG Yifanload("//rust:defs.bzl", "rust_library") 23*d4726bddSHONG Yifanload("//rust:rust_common.bzl", "BuildInfo") 24*d4726bddSHONG Yifan 25*d4726bddSHONG Yifan# buildifier: disable=bzl-visibility 26*d4726bddSHONG Yifanload("//rust/private:rustc.bzl", "get_linker_and_args") 27*d4726bddSHONG Yifan 28*d4726bddSHONG Yifan# buildifier: disable=bzl-visibility 29*d4726bddSHONG Yifanload("//rust/private:utils.bzl", "find_cc_toolchain", "get_lib_name_default", "get_preferred_artifact") 30*d4726bddSHONG Yifan 31*d4726bddSHONG Yifan# TODO(hlopko): use the more robust logic from rustc.bzl also here, through a reasonable API. 32*d4726bddSHONG Yifandef _get_libs_for_static_executable(dep): 33*d4726bddSHONG Yifan """find the libraries used for linking a static executable. 34*d4726bddSHONG Yifan 35*d4726bddSHONG Yifan Args: 36*d4726bddSHONG Yifan dep (Target): A cc_library target. 37*d4726bddSHONG Yifan 38*d4726bddSHONG Yifan Returns: 39*d4726bddSHONG Yifan depset: A depset[File] 40*d4726bddSHONG Yifan """ 41*d4726bddSHONG Yifan linker_inputs = dep[CcInfo].linking_context.linker_inputs.to_list() 42*d4726bddSHONG Yifan return depset([get_preferred_artifact(lib, use_pic = False) for li in linker_inputs for lib in li.libraries]) 43*d4726bddSHONG Yifan 44*d4726bddSHONG Yifandef rust_bindgen_library( 45*d4726bddSHONG Yifan name, 46*d4726bddSHONG Yifan header, 47*d4726bddSHONG Yifan cc_lib, 48*d4726bddSHONG Yifan bindgen_flags = None, 49*d4726bddSHONG Yifan bindgen_features = None, 50*d4726bddSHONG Yifan clang_flags = None, 51*d4726bddSHONG Yifan wrap_static_fns = False, 52*d4726bddSHONG Yifan **kwargs): 53*d4726bddSHONG Yifan """Generates a rust source file for `header`, and builds a rust_library. 54*d4726bddSHONG Yifan 55*d4726bddSHONG Yifan Arguments are the same as `rust_bindgen`, and `kwargs` are passed directly to rust_library. 56*d4726bddSHONG Yifan 57*d4726bddSHONG Yifan Args: 58*d4726bddSHONG Yifan name (str): A unique name for this target. 59*d4726bddSHONG Yifan header (str): The label of the .h file to generate bindings for. 60*d4726bddSHONG Yifan cc_lib (str): The label of the cc_library that contains the .h file. This is used to find the transitive includes. 61*d4726bddSHONG Yifan bindgen_flags (list, optional): Flags to pass directly to the bindgen executable. See https://rust-lang.github.io/rust-bindgen/ for details. 62*d4726bddSHONG Yifan bindgen_features (list, optional): The `features` attribute for the `rust_bindgen` target. 63*d4726bddSHONG Yifan clang_flags (list, optional): Flags to pass directly to the clang executable. 64*d4726bddSHONG Yifan wrap_static_fns (bool): Whether to create a separate .c file for static fns. Requires nightly toolchain, and a header that actually needs this feature (otherwise bindgen won't generate the file and Bazel complains", 65*d4726bddSHONG Yifan **kwargs: Arguments to forward to the underlying `rust_library` rule. 66*d4726bddSHONG Yifan """ 67*d4726bddSHONG Yifan 68*d4726bddSHONG Yifan tags = kwargs.get("tags") or [] 69*d4726bddSHONG Yifan if "tags" in kwargs: 70*d4726bddSHONG Yifan kwargs.pop("tags") 71*d4726bddSHONG Yifan 72*d4726bddSHONG Yifan sub_tags = tags + ([] if "manual" in tags else ["manual"]) 73*d4726bddSHONG Yifan 74*d4726bddSHONG Yifan bindgen_kwargs = {} 75*d4726bddSHONG Yifan for shared in ( 76*d4726bddSHONG Yifan "target_compatible_with", 77*d4726bddSHONG Yifan "exec_compatible_with", 78*d4726bddSHONG Yifan ): 79*d4726bddSHONG Yifan if shared in kwargs: 80*d4726bddSHONG Yifan bindgen_kwargs.update({shared: kwargs[shared]}) 81*d4726bddSHONG Yifan 82*d4726bddSHONG Yifan rust_bindgen( 83*d4726bddSHONG Yifan name = name + "__bindgen", 84*d4726bddSHONG Yifan header = header, 85*d4726bddSHONG Yifan cc_lib = cc_lib, 86*d4726bddSHONG Yifan bindgen_flags = bindgen_flags or [], 87*d4726bddSHONG Yifan features = bindgen_features, 88*d4726bddSHONG Yifan clang_flags = clang_flags or [], 89*d4726bddSHONG Yifan tags = sub_tags, 90*d4726bddSHONG Yifan wrap_static_fns = wrap_static_fns, 91*d4726bddSHONG Yifan **bindgen_kwargs 92*d4726bddSHONG Yifan ) 93*d4726bddSHONG Yifan 94*d4726bddSHONG Yifan tags = depset(tags + ["__bindgen", "no-clippy", "no-rustfmt"]).to_list() 95*d4726bddSHONG Yifan 96*d4726bddSHONG Yifan deps = kwargs.get("deps") or [] 97*d4726bddSHONG Yifan if "deps" in kwargs: 98*d4726bddSHONG Yifan kwargs.pop("deps") 99*d4726bddSHONG Yifan 100*d4726bddSHONG Yifan if wrap_static_fns: 101*d4726bddSHONG Yifan native.filegroup( 102*d4726bddSHONG Yifan name = name + "__bindgen_c_thunks", 103*d4726bddSHONG Yifan srcs = [":" + name + "__bindgen"], 104*d4726bddSHONG Yifan output_group = "bindgen_c_thunks", 105*d4726bddSHONG Yifan ) 106*d4726bddSHONG Yifan 107*d4726bddSHONG Yifan cc_library( 108*d4726bddSHONG Yifan name = name + "__bindgen_c_thunks_library", 109*d4726bddSHONG Yifan srcs = [":" + name + "__bindgen_c_thunks"], 110*d4726bddSHONG Yifan deps = [cc_lib], 111*d4726bddSHONG Yifan ) 112*d4726bddSHONG Yifan 113*d4726bddSHONG Yifan rust_library( 114*d4726bddSHONG Yifan name = name, 115*d4726bddSHONG Yifan srcs = [name + "__bindgen.rs"], 116*d4726bddSHONG Yifan deps = deps + [":" + name + "__bindgen"] + ([":" + name + "__bindgen_c_thunks_library"] if wrap_static_fns else []), 117*d4726bddSHONG Yifan tags = tags, 118*d4726bddSHONG Yifan **kwargs 119*d4726bddSHONG Yifan ) 120*d4726bddSHONG Yifan 121*d4726bddSHONG Yifandef _get_user_link_flags(cc_lib): 122*d4726bddSHONG Yifan linker_flags = [] 123*d4726bddSHONG Yifan 124*d4726bddSHONG Yifan for linker_input in cc_lib[CcInfo].linking_context.linker_inputs.to_list(): 125*d4726bddSHONG Yifan linker_flags.extend(linker_input.user_link_flags) 126*d4726bddSHONG Yifan 127*d4726bddSHONG Yifan return linker_flags 128*d4726bddSHONG Yifan 129*d4726bddSHONG Yifandef _generate_cc_link_build_info(ctx, cc_lib): 130*d4726bddSHONG Yifan """Produce the eqivilant cargo_build_script providers for use in linking the library. 131*d4726bddSHONG Yifan 132*d4726bddSHONG Yifan Args: 133*d4726bddSHONG Yifan ctx (ctx): The rule's context object 134*d4726bddSHONG Yifan cc_lib (Target): The `rust_bindgen.cc_lib` target. 135*d4726bddSHONG Yifan 136*d4726bddSHONG Yifan Returns: 137*d4726bddSHONG Yifan The `BuildInfo` provider. 138*d4726bddSHONG Yifan """ 139*d4726bddSHONG Yifan compile_data = [] 140*d4726bddSHONG Yifan 141*d4726bddSHONG Yifan rustc_flags = [] 142*d4726bddSHONG Yifan linker_search_paths = [] 143*d4726bddSHONG Yifan 144*d4726bddSHONG Yifan for linker_input in cc_lib[CcInfo].linking_context.linker_inputs.to_list(): 145*d4726bddSHONG Yifan for lib in linker_input.libraries: 146*d4726bddSHONG Yifan if lib.static_library: 147*d4726bddSHONG Yifan rustc_flags.append("-lstatic={}".format(get_lib_name_default(lib.static_library))) 148*d4726bddSHONG Yifan linker_search_paths.append(lib.static_library.dirname) 149*d4726bddSHONG Yifan compile_data.append(lib.static_library) 150*d4726bddSHONG Yifan elif lib.pic_static_library: 151*d4726bddSHONG Yifan rustc_flags.append("-lstatic={}".format(get_lib_name_default(lib.pic_static_library))) 152*d4726bddSHONG Yifan linker_search_paths.append(lib.pic_static_library.dirname) 153*d4726bddSHONG Yifan compile_data.append(lib.pic_static_library) 154*d4726bddSHONG Yifan 155*d4726bddSHONG Yifan if not compile_data: 156*d4726bddSHONG Yifan fail("No static libraries found in {}".format( 157*d4726bddSHONG Yifan cc_lib.label, 158*d4726bddSHONG Yifan )) 159*d4726bddSHONG Yifan 160*d4726bddSHONG Yifan rustc_flags_file = ctx.actions.declare_file("{}.rustc_flags".format(ctx.label.name)) 161*d4726bddSHONG Yifan ctx.actions.write( 162*d4726bddSHONG Yifan output = rustc_flags_file, 163*d4726bddSHONG Yifan content = "\n".join(rustc_flags), 164*d4726bddSHONG Yifan ) 165*d4726bddSHONG Yifan 166*d4726bddSHONG Yifan link_search_paths = ctx.actions.declare_file("{}.link_search_paths".format(ctx.label.name)) 167*d4726bddSHONG Yifan ctx.actions.write( 168*d4726bddSHONG Yifan output = link_search_paths, 169*d4726bddSHONG Yifan content = "\n".join([ 170*d4726bddSHONG Yifan "-Lnative=${{pwd}}/{}".format(path) 171*d4726bddSHONG Yifan for path in depset(linker_search_paths).to_list() 172*d4726bddSHONG Yifan ]), 173*d4726bddSHONG Yifan ) 174*d4726bddSHONG Yifan 175*d4726bddSHONG Yifan return BuildInfo( 176*d4726bddSHONG Yifan compile_data = depset(compile_data), 177*d4726bddSHONG Yifan dep_env = None, 178*d4726bddSHONG Yifan flags = rustc_flags_file, 179*d4726bddSHONG Yifan # linker_flags is provided via CcInfo 180*d4726bddSHONG Yifan linker_flags = None, 181*d4726bddSHONG Yifan link_search_paths = link_search_paths, 182*d4726bddSHONG Yifan out_dir = None, 183*d4726bddSHONG Yifan rustc_env = None, 184*d4726bddSHONG Yifan ) 185*d4726bddSHONG Yifan 186*d4726bddSHONG Yifandef _rust_bindgen_impl(ctx): 187*d4726bddSHONG Yifan # nb. We can't grab the cc_library`s direct headers, so a header must be provided. 188*d4726bddSHONG Yifan cc_lib = ctx.attr.cc_lib 189*d4726bddSHONG Yifan header = ctx.file.header 190*d4726bddSHONG Yifan cc_header_list = ctx.attr.cc_lib[CcInfo].compilation_context.headers.to_list() 191*d4726bddSHONG Yifan if header not in cc_header_list: 192*d4726bddSHONG Yifan fail("Header {} is not in {}'s transitive headers.".format(ctx.attr.header, cc_lib), "header") 193*d4726bddSHONG Yifan 194*d4726bddSHONG Yifan toolchain = ctx.toolchains[Label("//bindgen:toolchain_type")] 195*d4726bddSHONG Yifan bindgen_bin = toolchain.bindgen 196*d4726bddSHONG Yifan clang_bin = toolchain.clang 197*d4726bddSHONG Yifan libclang = toolchain.libclang 198*d4726bddSHONG Yifan libstdcxx = toolchain.libstdcxx 199*d4726bddSHONG Yifan 200*d4726bddSHONG Yifan output = ctx.outputs.out 201*d4726bddSHONG Yifan 202*d4726bddSHONG Yifan cc_toolchain, feature_configuration = find_cc_toolchain(ctx = ctx) 203*d4726bddSHONG Yifan 204*d4726bddSHONG Yifan tools = depset(([clang_bin] if clang_bin else []), transitive = [cc_toolchain.all_files]) 205*d4726bddSHONG Yifan 206*d4726bddSHONG Yifan # libclang should only have 1 output file 207*d4726bddSHONG Yifan libclang_dir = _get_libs_for_static_executable(libclang).to_list()[0].dirname 208*d4726bddSHONG Yifan 209*d4726bddSHONG Yifan env = { 210*d4726bddSHONG Yifan "LIBCLANG_PATH": libclang_dir, 211*d4726bddSHONG Yifan "RUST_BACKTRACE": "1", 212*d4726bddSHONG Yifan } 213*d4726bddSHONG Yifan if clang_bin: 214*d4726bddSHONG Yifan env["CLANG_PATH"] = clang_bin.path 215*d4726bddSHONG Yifan 216*d4726bddSHONG Yifan args = ctx.actions.args() 217*d4726bddSHONG Yifan 218*d4726bddSHONG Yifan # Configure Bindgen Arguments 219*d4726bddSHONG Yifan args.add_all(ctx.attr.bindgen_flags) 220*d4726bddSHONG Yifan args.add(header) 221*d4726bddSHONG Yifan args.add("--output", output) 222*d4726bddSHONG Yifan 223*d4726bddSHONG Yifan wrap_static_fns = getattr(ctx.attr, "wrap_static_fns", False) 224*d4726bddSHONG Yifan 225*d4726bddSHONG Yifan c_output = None 226*d4726bddSHONG Yifan if wrap_static_fns: 227*d4726bddSHONG Yifan if "--wrap-static-fns" in ctx.attr.bindgen_flags: 228*d4726bddSHONG Yifan fail("Do not pass `--wrap-static-fns` to `bindgen_flags, it's added automatically." + 229*d4726bddSHONG Yifan "The generated C file is accesible in the `bindgen_c_thunks` output group.") 230*d4726bddSHONG Yifan c_output = ctx.actions.declare_file(ctx.label.name + ".bindgen_c_thunks.c") 231*d4726bddSHONG Yifan args.add("--experimental") 232*d4726bddSHONG Yifan args.add("--wrap-static-fns") 233*d4726bddSHONG Yifan args.add("--wrap-static-fns-path") 234*d4726bddSHONG Yifan args.add(c_output.path) 235*d4726bddSHONG Yifan 236*d4726bddSHONG Yifan # Vanilla usage of bindgen produces formatted output, here we do the same if we have `rustfmt` in our toolchain. 237*d4726bddSHONG Yifan rustfmt_toolchain = ctx.toolchains[Label("//rust/rustfmt:toolchain_type")] 238*d4726bddSHONG Yifan if rustfmt_toolchain and toolchain.default_rustfmt: 239*d4726bddSHONG Yifan # Bindgen is able to find rustfmt using the RUSTFMT environment variable 240*d4726bddSHONG Yifan env.update({"RUSTFMT": rustfmt_toolchain.rustfmt.path}) 241*d4726bddSHONG Yifan tools = depset(transitive = [tools, rustfmt_toolchain.all_files]) 242*d4726bddSHONG Yifan else: 243*d4726bddSHONG Yifan args.add("--no-rustfmt-bindings") 244*d4726bddSHONG Yifan 245*d4726bddSHONG Yifan # Configure Clang Arguments 246*d4726bddSHONG Yifan args.add("--") 247*d4726bddSHONG Yifan 248*d4726bddSHONG Yifan compile_variables = cc_common.create_compile_variables( 249*d4726bddSHONG Yifan cc_toolchain = cc_toolchain, 250*d4726bddSHONG Yifan feature_configuration = feature_configuration, 251*d4726bddSHONG Yifan include_directories = cc_lib[CcInfo].compilation_context.includes, 252*d4726bddSHONG Yifan quote_include_directories = cc_lib[CcInfo].compilation_context.quote_includes, 253*d4726bddSHONG Yifan system_include_directories = depset( 254*d4726bddSHONG Yifan transitive = [cc_lib[CcInfo].compilation_context.system_includes], 255*d4726bddSHONG Yifan direct = cc_toolchain.built_in_include_directories, 256*d4726bddSHONG Yifan ), 257*d4726bddSHONG Yifan user_compile_flags = ctx.attr.clang_flags, 258*d4726bddSHONG Yifan ) 259*d4726bddSHONG Yifan compile_flags = cc_common.get_memory_inefficient_command_line( 260*d4726bddSHONG Yifan feature_configuration = feature_configuration, 261*d4726bddSHONG Yifan action_name = CPP_COMPILE_ACTION_NAME, 262*d4726bddSHONG Yifan variables = compile_variables, 263*d4726bddSHONG Yifan ) 264*d4726bddSHONG Yifan 265*d4726bddSHONG Yifan # Bindgen forcibly uses clang. 266*d4726bddSHONG Yifan # It's possible that the selected cc_toolchain isn't clang, and may specify flags which clang doesn't recognise. 267*d4726bddSHONG Yifan # Ideally we could depend on a more specific toolchain, requesting one which is specifically clang via some constraint. 268*d4726bddSHONG Yifan # Unfortunately, we can't currently rely on this, so instead we filter only to flags we know clang supports. 269*d4726bddSHONG Yifan # We can add extra flags here as needed. 270*d4726bddSHONG Yifan flags_known_to_clang = ("-I", "-iquote", "-isystem", "--sysroot", "--gcc-toolchain") 271*d4726bddSHONG Yifan open_arg = False 272*d4726bddSHONG Yifan for arg in compile_flags: 273*d4726bddSHONG Yifan if open_arg: 274*d4726bddSHONG Yifan args.add(arg) 275*d4726bddSHONG Yifan open_arg = False 276*d4726bddSHONG Yifan continue 277*d4726bddSHONG Yifan 278*d4726bddSHONG Yifan # The cc_toolchain merged these flags into its returned flags - don't strip these out. 279*d4726bddSHONG Yifan if arg in ctx.attr.clang_flags: 280*d4726bddSHONG Yifan args.add(arg) 281*d4726bddSHONG Yifan continue 282*d4726bddSHONG Yifan 283*d4726bddSHONG Yifan if not arg.startswith(flags_known_to_clang): 284*d4726bddSHONG Yifan continue 285*d4726bddSHONG Yifan 286*d4726bddSHONG Yifan args.add(arg) 287*d4726bddSHONG Yifan 288*d4726bddSHONG Yifan if arg in flags_known_to_clang: 289*d4726bddSHONG Yifan open_arg = True 290*d4726bddSHONG Yifan continue 291*d4726bddSHONG Yifan 292*d4726bddSHONG Yifan _, _, linker_env = get_linker_and_args(ctx, ctx.attr, "bin", cc_toolchain, feature_configuration, None) 293*d4726bddSHONG Yifan env.update(**linker_env) 294*d4726bddSHONG Yifan 295*d4726bddSHONG Yifan # Set the dynamic linker search path so that clang uses the libstdcxx from the toolchain. 296*d4726bddSHONG Yifan # DYLD_LIBRARY_PATH is LD_LIBRARY_PATH on macOS. 297*d4726bddSHONG Yifan if libstdcxx: 298*d4726bddSHONG Yifan env["LD_LIBRARY_PATH"] = ":".join([f.dirname for f in _get_libs_for_static_executable(libstdcxx).to_list()]) 299*d4726bddSHONG Yifan env["DYLD_LIBRARY_PATH"] = env["LD_LIBRARY_PATH"] 300*d4726bddSHONG Yifan 301*d4726bddSHONG Yifan ctx.actions.run( 302*d4726bddSHONG Yifan executable = bindgen_bin, 303*d4726bddSHONG Yifan inputs = depset( 304*d4726bddSHONG Yifan [header], 305*d4726bddSHONG Yifan transitive = [ 306*d4726bddSHONG Yifan cc_lib[CcInfo].compilation_context.headers, 307*d4726bddSHONG Yifan _get_libs_for_static_executable(libclang), 308*d4726bddSHONG Yifan ] + ([ 309*d4726bddSHONG Yifan _get_libs_for_static_executable(libstdcxx), 310*d4726bddSHONG Yifan ] if libstdcxx else []), 311*d4726bddSHONG Yifan ), 312*d4726bddSHONG Yifan outputs = [output] + ([c_output] if wrap_static_fns else []), 313*d4726bddSHONG Yifan mnemonic = "RustBindgen", 314*d4726bddSHONG Yifan progress_message = "Generating bindings for {}..".format(header.path), 315*d4726bddSHONG Yifan env = env, 316*d4726bddSHONG Yifan arguments = [args], 317*d4726bddSHONG Yifan tools = tools, 318*d4726bddSHONG Yifan # ctx.actions.run now require (through a buildifier check) that we 319*d4726bddSHONG Yifan # specify this 320*d4726bddSHONG Yifan toolchain = None, 321*d4726bddSHONG Yifan ) 322*d4726bddSHONG Yifan 323*d4726bddSHONG Yifan return [ 324*d4726bddSHONG Yifan _generate_cc_link_build_info(ctx, cc_lib), 325*d4726bddSHONG Yifan # As in https://github.com/bazelbuild/rules_rust/pull/2361, we want 326*d4726bddSHONG Yifan # to link cc_lib to the direct parent (rlib) using `-lstatic=<cc_lib>` 327*d4726bddSHONG Yifan # rustc flag. Hence, we do not need to provide the whole CcInfo of 328*d4726bddSHONG Yifan # cc_lib because it will cause the downstream binary to link the cc_lib 329*d4726bddSHONG Yifan # again. The CcInfo here only contains the custom link flags (i.e. 330*d4726bddSHONG Yifan # linkopts attribute) specified by users in cc_lib. 331*d4726bddSHONG Yifan CcInfo( 332*d4726bddSHONG Yifan linking_context = cc_common.create_linking_context( 333*d4726bddSHONG Yifan linker_inputs = depset([cc_common.create_linker_input( 334*d4726bddSHONG Yifan owner = ctx.label, 335*d4726bddSHONG Yifan user_link_flags = _get_user_link_flags(cc_lib), 336*d4726bddSHONG Yifan )]), 337*d4726bddSHONG Yifan ), 338*d4726bddSHONG Yifan ), 339*d4726bddSHONG Yifan OutputGroupInfo( 340*d4726bddSHONG Yifan bindgen_bindings = depset([output]), 341*d4726bddSHONG Yifan bindgen_c_thunks = depset(([c_output] if wrap_static_fns else [])), 342*d4726bddSHONG Yifan ), 343*d4726bddSHONG Yifan ] 344*d4726bddSHONG Yifan 345*d4726bddSHONG Yifanrust_bindgen = rule( 346*d4726bddSHONG Yifan doc = "Generates a rust source file from a cc_library and a header.", 347*d4726bddSHONG Yifan implementation = _rust_bindgen_impl, 348*d4726bddSHONG Yifan attrs = { 349*d4726bddSHONG Yifan "bindgen_flags": attr.string_list( 350*d4726bddSHONG Yifan doc = "Flags to pass directly to the bindgen executable. See https://rust-lang.github.io/rust-bindgen/ for details.", 351*d4726bddSHONG Yifan ), 352*d4726bddSHONG Yifan "cc_lib": attr.label( 353*d4726bddSHONG Yifan doc = "The cc_library that contains the `.h` file. This is used to find the transitive includes.", 354*d4726bddSHONG Yifan providers = [CcInfo], 355*d4726bddSHONG Yifan mandatory = True, 356*d4726bddSHONG Yifan ), 357*d4726bddSHONG Yifan "clang_flags": attr.string_list( 358*d4726bddSHONG Yifan doc = "Flags to pass directly to the clang executable.", 359*d4726bddSHONG Yifan ), 360*d4726bddSHONG Yifan "header": attr.label( 361*d4726bddSHONG Yifan doc = "The `.h` file to generate bindings for.", 362*d4726bddSHONG Yifan allow_single_file = True, 363*d4726bddSHONG Yifan mandatory = True, 364*d4726bddSHONG Yifan ), 365*d4726bddSHONG Yifan "wrap_static_fns": attr.bool( 366*d4726bddSHONG Yifan doc = "Whether to create a separate .c file for static fns. Requires nightly toolchain, and a header that actually needs this feature (otherwise bindgen won't generate the file and Bazel complains).", 367*d4726bddSHONG Yifan default = False, 368*d4726bddSHONG Yifan ), 369*d4726bddSHONG Yifan "_cc_toolchain": attr.label( 370*d4726bddSHONG Yifan default = Label("@bazel_tools//tools/cpp:current_cc_toolchain"), 371*d4726bddSHONG Yifan ), 372*d4726bddSHONG Yifan "_process_wrapper": attr.label( 373*d4726bddSHONG Yifan default = Label("//util/process_wrapper"), 374*d4726bddSHONG Yifan executable = True, 375*d4726bddSHONG Yifan allow_single_file = True, 376*d4726bddSHONG Yifan cfg = "exec", 377*d4726bddSHONG Yifan ), 378*d4726bddSHONG Yifan }, 379*d4726bddSHONG Yifan outputs = {"out": "%{name}.rs"}, 380*d4726bddSHONG Yifan fragments = ["cpp"], 381*d4726bddSHONG Yifan toolchains = [ 382*d4726bddSHONG Yifan config_common.toolchain_type("//bindgen:toolchain_type"), 383*d4726bddSHONG Yifan config_common.toolchain_type("//rust:toolchain_type"), 384*d4726bddSHONG Yifan config_common.toolchain_type("//rust/rustfmt:toolchain_type", mandatory = False), 385*d4726bddSHONG Yifan config_common.toolchain_type("@bazel_tools//tools/cpp:toolchain_type"), 386*d4726bddSHONG Yifan ], 387*d4726bddSHONG Yifan) 388*d4726bddSHONG Yifan 389*d4726bddSHONG Yifandef _rust_bindgen_toolchain_impl(ctx): 390*d4726bddSHONG Yifan return platform_common.ToolchainInfo( 391*d4726bddSHONG Yifan bindgen = ctx.executable.bindgen, 392*d4726bddSHONG Yifan clang = ctx.executable.clang, 393*d4726bddSHONG Yifan libclang = ctx.attr.libclang, 394*d4726bddSHONG Yifan libstdcxx = ctx.attr.libstdcxx, 395*d4726bddSHONG Yifan default_rustfmt = ctx.attr.default_rustfmt, 396*d4726bddSHONG Yifan ) 397*d4726bddSHONG Yifan 398*d4726bddSHONG Yifanrust_bindgen_toolchain = rule( 399*d4726bddSHONG Yifan _rust_bindgen_toolchain_impl, 400*d4726bddSHONG Yifan doc = """\ 401*d4726bddSHONG YifanThe tools required for the `rust_bindgen` rule. 402*d4726bddSHONG Yifan 403*d4726bddSHONG YifanThis rule depends on the [`bindgen`](https://crates.io/crates/bindgen) binary crate, and it 404*d4726bddSHONG Yifanin turn depends on both a clang binary and the clang library. To obtain these dependencies, 405*d4726bddSHONG Yifan`rust_bindgen_dependencies` imports bindgen and its dependencies. 406*d4726bddSHONG Yifan 407*d4726bddSHONG Yifan```python 408*d4726bddSHONG Yifanload("@rules_rust//bindgen:defs.bzl", "rust_bindgen_toolchain") 409*d4726bddSHONG Yifan 410*d4726bddSHONG Yifanrust_bindgen_toolchain( 411*d4726bddSHONG Yifan name = "bindgen_toolchain_impl", 412*d4726bddSHONG Yifan bindgen = "//my/rust:bindgen", 413*d4726bddSHONG Yifan clang = "//my/clang:clang", 414*d4726bddSHONG Yifan libclang = "//my/clang:libclang.so", 415*d4726bddSHONG Yifan libstdcxx = "//my/cpp:libstdc++", 416*d4726bddSHONG Yifan) 417*d4726bddSHONG Yifan 418*d4726bddSHONG Yifantoolchain( 419*d4726bddSHONG Yifan name = "bindgen_toolchain", 420*d4726bddSHONG Yifan toolchain = "bindgen_toolchain_impl", 421*d4726bddSHONG Yifan toolchain_type = "@rules_rust//bindgen:toolchain_type", 422*d4726bddSHONG Yifan) 423*d4726bddSHONG Yifan``` 424*d4726bddSHONG Yifan 425*d4726bddSHONG YifanThis toolchain will then need to be registered in the current `WORKSPACE`. 426*d4726bddSHONG YifanFor additional information, see the [Bazel toolchains documentation](https://docs.bazel.build/versions/master/toolchains.html). 427*d4726bddSHONG Yifan""", 428*d4726bddSHONG Yifan attrs = { 429*d4726bddSHONG Yifan "bindgen": attr.label( 430*d4726bddSHONG Yifan doc = "The label of a `bindgen` executable.", 431*d4726bddSHONG Yifan executable = True, 432*d4726bddSHONG Yifan cfg = "exec", 433*d4726bddSHONG Yifan ), 434*d4726bddSHONG Yifan "clang": attr.label( 435*d4726bddSHONG Yifan doc = "The label of a `clang` executable.", 436*d4726bddSHONG Yifan executable = True, 437*d4726bddSHONG Yifan cfg = "exec", 438*d4726bddSHONG Yifan allow_files = True, 439*d4726bddSHONG Yifan ), 440*d4726bddSHONG Yifan "default_rustfmt": attr.bool( 441*d4726bddSHONG Yifan doc = "If set, `rust_bindgen` targets will always format generated sources with `rustfmt`.", 442*d4726bddSHONG Yifan mandatory = False, 443*d4726bddSHONG Yifan default = True, 444*d4726bddSHONG Yifan ), 445*d4726bddSHONG Yifan "libclang": attr.label( 446*d4726bddSHONG Yifan doc = "A cc_library that provides bindgen's runtime dependency on libclang.", 447*d4726bddSHONG Yifan cfg = "exec", 448*d4726bddSHONG Yifan providers = [CcInfo], 449*d4726bddSHONG Yifan allow_files = True, 450*d4726bddSHONG Yifan ), 451*d4726bddSHONG Yifan "libstdcxx": attr.label( 452*d4726bddSHONG Yifan doc = "A cc_library that satisfies libclang's libstdc++ dependency. This is used to make the execution of clang hermetic. If None, system libraries will be used instead.", 453*d4726bddSHONG Yifan cfg = "exec", 454*d4726bddSHONG Yifan providers = [CcInfo], 455*d4726bddSHONG Yifan mandatory = False, 456*d4726bddSHONG Yifan allow_files = True, 457*d4726bddSHONG Yifan ), 458*d4726bddSHONG Yifan }, 459*d4726bddSHONG Yifan) 460