blob: bc4141773eae2a764cf4071b8156402e236cc954 [file]
# Copyright 2026 The Fuchsia Authors. All rights reserved.
# Use of this source code is governed by a BSD-style license that can be
# found in the LICENSE file.
"""A rust_library backed by a FIDL library."""
load("@rules_rust//rust:defs.bzl", "rust_library")
visibility("private")
def fidl_rust_library(
*,
name,
fidl_library_name,
fidl_ir_json,
deps,
contains_drivers,
testonly,
visibility):
"""
Generates a `rust_library()` providing the generated Rust bindings for a given FIDL library.
Args:
name: String base name of the `rust_library()` target.
fidl_library_name: String name of the FIDL library for which bindings are generated.
fidl_ir_json: `Label` pointing to a single file containing the FIDL IR
representation of the `fidl_library_name` library.
deps: List of `Label`s for FIDL libraries that the `fidl_library_name` library depends on.
contains_drivers: Boolean indicating whether the `fidl_library_name`
library supports drivers.
testonly: usual meaning.
visibility: usual meaning.
"""
_fidl_rust_library_flavor("fidl", name, fidl_library_name, fidl_ir_json, deps, contains_drivers, testonly, visibility)
_fidl_rust_library_flavor("common", name, fidl_library_name, fidl_ir_json, deps, contains_drivers, testonly, ["//visibility:private"])
_fidl_rust_library_flavor("fdomain", name, fidl_library_name, fidl_ir_json, deps, contains_drivers, testonly, visibility)
_fidl_rust_library_flex("fidl", name, fidl_library_name, testonly, visibility)
_fidl_rust_library_flex("fdomain", name, fidl_library_name, testonly, visibility)
def _fidl_rust_flavor_crate_name(fidl_library_name, flavor):
base = fidl_library_name.replace(".", "_")
if flavor == "fidl":
return "fidl_%s" % base
elif flavor == "common":
return "fidl_%s_common" % base
elif flavor == "fdomain":
return "fdomain_%s" % base
else:
fail("Unknown flavor: %s" % flavor)
def _fidl_rust_flavor_file_name(name, flavor):
base = name.replace(".", "_")
if flavor == "fidl":
return "%s.rs" % base
elif flavor == "common":
return "%s_common.rs" % base
elif flavor == "fdomain":
return "%s__fdomain.rs" % base
else:
fail("Unknown flavor: %s" % flavor)
def _fidl_rust_flavor_label_suffix(flavor):
if flavor == "fidl":
return "rust"
elif flavor == "common":
return "rust_common"
elif flavor == "fdomain":
return "rust_fdomain"
else:
fail("Unknown flavor: %s" % flavor)
def _fidl_rust_flavor_label_name(label_name, flavor):
return label_name + "_" + _fidl_rust_flavor_label_suffix(flavor)
def _fidl_rust_flavor_label(label, flavor):
return "//%s:%s" % (label.package, _fidl_rust_flavor_label_name(label.name, flavor))
def _fidl_rust_library_flavor(flavor, name, fidl_library_name, fidl_ir_json, deps, contains_drivers, testonly, visibility):
flavor_label = name + "_" + _fidl_rust_flavor_label_suffix(flavor)
fidlgen_label = flavor_label + "_fidlgen"
if flavor == "common":
use_common = ""
else:
use_common = _fidl_rust_flavor_crate_name(fidl_library_name, "common")
_fidlgen_rust(
name = fidlgen_label,
fidl_ir_json = fidl_ir_json,
out = "bindings/rust/%s.rs" % _fidl_rust_flavor_file_name(name, flavor),
contains_drivers = contains_drivers,
common = (flavor == "common"),
fdomain = (flavor == "fdomain"),
use_common = use_common,
testonly = testonly,
visibility = ["//visibility:private"],
)
library_deps = [
"//sdk/rust/zx-status",
"//src/lib/fidl/rust/fidl",
"//third_party/rust_crates/vendor:bitflags",
"//third_party/rust_crates/vendor:futures",
]
if flavor == "fdomain":
library_deps.append("//src/lib/fdomain/client")
for dep in deps:
if Label(dep) == Label("//zircon/vdso/zx"):
continue
library_deps.append(_fidl_rust_flavor_label(dep, flavor))
if flavor != "common":
library_deps.append(":" + _fidl_rust_flavor_label_name(fidl_library_name, "common"))
if contains_drivers:
# TODO(https://fxbug.dev/503359085): driver transport support
# library_deps += [
# "//src/lib/fidl/rust/fidl_driver",
# "//sdk/lib/driver/runtime/rust",
# ]
pass
# `select()` must be appended last.
library_deps += select({
"@platforms//os:fuchsia": ["//sdk/rust/zx"],
"//conditions:default": [],
})
rust_library(
name = flavor_label,
crate_name = _fidl_rust_flavor_crate_name(fidl_library_name, flavor),
srcs = [fidlgen_label],
deps = library_deps,
edition = "2018",
tags = ["noclippy"],
testonly = testonly,
visibility = visibility,
)
def _fidl_rust_library_flex(flavor, name, fidl_library_name, testonly, visibility):
original_label = name + "_" + _fidl_rust_flavor_label_suffix(flavor)
original_crate_name = _fidl_rust_flavor_crate_name(fidl_library_name, flavor)
flex_label = original_label + "_flex"
flex_generate_label = flex_label + "_generate"
base_library_name = fidl_library_name.replace(".", "_")
flex_crate_name = "flex_%s" % base_library_name
flex_file_name = "bindings/rust/%s_%s_flex.rs" % (name.replace(".", "_"), flavor)
native.genrule(
name = flex_generate_label,
outs = [flex_file_name],
cmd = "echo 'pub use %s::*;' > $@" % original_crate_name,
testonly = testonly,
visibility = ["//visibility:private"],
)
rust_library(
name = flex_label,
crate_name = flex_crate_name,
srcs = [flex_generate_label],
deps = [":" + original_label],
edition = "2024",
tags = ["noclippy"],
testonly = testonly,
visibility = visibility,
)
def _fidlgen_rust_impl(ctx):
if ctx.attr.common != (ctx.attr.use_common == ""):
fail("'use_common' must be empty if and only if `common` is True.")
ir = ctx.file.fidl_ir_json
rust_toolchain = ctx.toolchains["@rules_rust//rust:toolchain_type"]
rustfmt = rust_toolchain.rustfmt
arguments = [
"--json",
ir.path,
"--output-filename",
ctx.outputs.out.path,
"--rustfmt",
rustfmt.path,
]
if ctx.attr.contains_drivers:
arguments.append("--include-drivers")
if ctx.attr.common:
arguments.append("--common")
if ctx.attr.fdomain:
arguments.append("--fdomain")
if ctx.attr.use_common != "":
arguments.append("--use_common=" + ctx.attr.use_common)
ctx.actions.run(
executable = ctx.executable._fidlgen_tool,
arguments = arguments,
inputs = [ir, rustfmt],
tools = rust_toolchain.all_files,
outputs = [ctx.outputs.out],
mnemonic = "FidlGenRust",
)
return [
DefaultInfo(files = depset([ctx.outputs.out])),
]
_fidlgen_rust = rule(
implementation = _fidlgen_rust_impl,
toolchains = ["@rules_rust//rust:toolchain_type"],
attrs = {
"fidl_ir_json": attr.label(
doc = "The FIDL IR for which to generate code.",
allow_single_file = True,
mandatory = True,
),
"contains_drivers": attr.bool(
doc = "Indicates if any of the FIDL files contain the driver transport or " +
"references to the driver transport.",
mandatory = True,
),
"common": attr.bool(
doc = "If `True`, generate only the common (non-resource) data structures.",
default = False,
),
"fdomain": attr.bool(
doc = "If `True`, generate FDomain bindings.",
default = False,
),
"use_common": attr.string(
doc = "If not empty, use the given crate name for the common (non-resource) data structures.",
default = "",
),
"_fidlgen_tool": attr.label(
doc = "fidlgen_rust tool.",
executable = True,
cfg = "exec",
default = "@//tools/fidl/fidlgen_rust",
),
"out": attr.output(
doc = "Output filename.",
mandatory = True,
),
},
)