blob: 649510ba3e57436122402c308a8e782a64e112a9 [file] [log] [blame] [edit]
# Copyright lowRISC contributors.
# Licensed under the Apache License, Version 2.0, see LICENSE for details.
# SPDX-License-Identifier: Apache-2.0
load("@rules_cc//cc:find_cc_toolchain.bzl", "find_cc_toolchain")
"""Rust generation rules for `ujson`."""
def _ujson_rust(ctx):
cc_toolchain = find_cc_toolchain(ctx).cc
module = ctx.actions.declare_file("{}.rs".format(ctx.label.name))
ujson_lib = ctx.attr.ujson_lib[CcInfo].compilation_context.headers.to_list()
# Get the include search path for ujson.
ujson_lib_root = ctx.attr.ujson_lib[CcInfo].compilation_context.quote_includes.to_list()
srcs = []
includes = []
for src in ctx.attr.srcs:
srcs.extend(src[CcInfo].compilation_context.direct_public_headers)
includes.extend(src[CcInfo].compilation_context.headers.to_list())
# TODO(cfrantz): Is there a better way to find the `rustfmt` binary?
rustfmt_files = ctx.attr._rustfmt.data_runfiles.files.to_list()
rustfmt = [f for f in rustfmt_files if f.basename == "rustfmt"][0]
defines = ["-D{}".format(d) for d in ctx.attr.defines]
# The pipeline for generating rust code from a ujson header file:
# 1. Preprocess the file with RUST_PREPROCESSOR_EMIT
# 2. Grep out all the preprocessor noise (which starts with `#`).
# 3. Substitute all `rust_attr` for `#`, thus creating rust attributes.
# 4. Format it with `rustfmt` so it looks nice and can be inspected.
command = """
{preprocessor} -nostdinc -I{ujson_lib_root_includes} \
-DRUST_PREPROCESSOR_EMIT=1 -DNOSTDINC=1 {defines} $@ \
| grep -v '#' \
| sed -e "s/rust_attr/#/g" \
| {rustfmt} > {module}""".format(
preprocessor = cc_toolchain.preprocessor_executable,
defines = " ".join(defines),
module = module.path,
rustfmt = rustfmt.path,
ujson_lib_root_includes = " -I".join(ujson_lib_root),
)
ctx.actions.run_shell(
outputs = [module],
inputs = ujson_lib + srcs + includes,
tools = cc_toolchain.all_files.to_list() + rustfmt_files,
arguments = [src.path for src in srcs],
command = command,
)
return [
DefaultInfo(files = depset([module]), runfiles = ctx.runfiles([module])),
]
ujson_rust = rule(
implementation = _ujson_rust,
attrs = {
"srcs": attr.label_list(
providers = [CcInfo],
doc = "ujson cc_library targets to generate Rust for",
),
"defines": attr.string_list(
doc = "C preprocessor defines",
),
"ujson_lib": attr.label(
default = "//sw/device/lib/ujson",
doc = "Location of the ujson library",
providers = [CcInfo],
),
"_cc_toolchain": attr.label(default = Label("@bazel_tools//tools/cpp:current_cc_toolchain")),
"_rustfmt": attr.label(
default = "@rules_rust//rust/toolchain:current_rustfmt_files",
cfg = "exec",
),
},
toolchains = ["@rules_cc//cc:toolchain_type"],
)