blob: 9388765130a74cc857a110f486be4415e3897a85 [file] [log] [blame]
Chris Frantz32156692022-06-21 22:03:26 -07001# Copyright lowRISC contributors.
2# Licensed under the Apache License, Version 2.0, see LICENSE for details.
3# SPDX-License-Identifier: Apache-2.0
4
5load("@rules_cc//cc:find_cc_toolchain.bzl", "find_cc_toolchain")
6
7"""Rust generation rules for `ujson`."""
8
9def _ujson_rust(ctx):
10 cc_toolchain = find_cc_toolchain(ctx).cc
11 module = ctx.actions.declare_file("{}.rs".format(ctx.label.name))
12 ujson_lib = ctx.attr.ujson_lib[CcInfo].compilation_context.headers.to_list()
13
14 srcs = []
15 for src in ctx.attr.srcs:
16 srcs.extend(src[CcInfo].compilation_context.direct_public_headers)
17
18 # TODO(cfrantz): Is there a better way to find the `rustfmt` binary?
19 rustfmt_files = ctx.attr._rustfmt.data_runfiles.files.to_list()
20 rustfmt = [f for f in rustfmt_files if f.basename == "rustfmt"][0]
21
Chris Frantza9413192022-08-04 21:03:00 -070022 defines = ["-D{}".format(d) for d in ctx.attr.defines]
23
Chris Frantz32156692022-06-21 22:03:26 -070024 # The pipeline for generating rust code from a ujson header file:
25 # 1. Preprocess the file with RUST_PREPROCESSOR_EMIT
26 # 2. Grep out all the preprocessor noise (which starts with `#`).
27 # 3. Substitute all `rust_attr` for `#`, thus creating rust attributes.
28 # 4. Format it with `rustfmt` so it looks nice and can be inspected.
29 command = """
Chris Frantza9413192022-08-04 21:03:00 -070030 {preprocessor} -nostdinc -I. -DRUST_PREPROCESSOR_EMIT=1 -DNOSTDINC=1 {defines} $@ \
Chris Frantz32156692022-06-21 22:03:26 -070031 | grep -v '#' \
32 | sed -e "s/rust_attr/#/g" \
33 | {rustfmt} > {module}""".format(
34 preprocessor = cc_toolchain.preprocessor_executable,
Chris Frantza9413192022-08-04 21:03:00 -070035 defines = " ".join(defines),
Chris Frantz32156692022-06-21 22:03:26 -070036 module = module.path,
37 rustfmt = rustfmt.path,
38 )
39
40 ctx.actions.run_shell(
41 outputs = [module],
42 inputs = ujson_lib + srcs,
43 tools = cc_toolchain.all_files.to_list() + rustfmt_files,
44 arguments = [src.path for src in srcs],
45 command = command,
46 )
47 return [
48 DefaultInfo(files = depset([module]), runfiles = ctx.runfiles([module])),
49 ]
50
51ujson_rust = rule(
52 implementation = _ujson_rust,
53 attrs = {
54 "srcs": attr.label_list(
55 providers = [CcInfo],
56 doc = "ujson cc_library targets to generate Rust for",
57 ),
Chris Frantza9413192022-08-04 21:03:00 -070058 "defines": attr.string_list(
59 doc = "C preprocessor defines",
60 ),
Chris Frantz32156692022-06-21 22:03:26 -070061 "ujson_lib": attr.label(
62 default = "//sw/device/lib/ujson",
63 doc = "Location of the ujson library",
64 providers = [CcInfo],
65 ),
66 "_cc_toolchain": attr.label(default = Label("@bazel_tools//tools/cpp:current_cc_toolchain")),
67 "_rustfmt": attr.label(
68 default = "@rules_rust//rust/toolchain:current_exec_rustfmt_files",
69 cfg = "exec",
70 ),
71 },
72 toolchains = ["@rules_cc//cc:toolchain_type"],
73)