xref: /aosp_15_r20/external/bazelbuild-rules_rust/bindgen/private/bindgen.bzl (revision d4726bddaa87cc4778e7472feed243fa4b6c267f)
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