Introduce a Bazel rule named `cc_bindings_from_rust`.
This is a small, incremental improvement over directly using `genrule`
in `cc_bindings_from_rs/test/functions/BUILD`:
1. It avoids having to redundantly mention "function.rs" twice: once as
`srcs` of a `rust_library` rule, and once as `srcs` of `genrule`.
2. It lays the groundwork for working later on passing the actual
rustc cmdline arguments to the `cc_bindings_from_rs` library
(rather than hardcoding `--crate-type=lib`, `--codegen=panic=abort`,
etc which for now happens before and after this CL).
This is the main motivation for this CL - this future work is
needed to unblock b/254097223.
3. It prevents _some_ duplication in the future - when introducing more
end-to-end tests (i.e. golden tests) we can reuse the new rule
(instead of duplicating the `genrule`).
PiperOrigin-RevId: 487261849
diff --git a/cc_bindings_from_rs/bazel_support/BUILD b/cc_bindings_from_rs/bazel_support/BUILD
new file mode 100644
index 0000000..3b88220
--- /dev/null
+++ b/cc_bindings_from_rs/bazel_support/BUILD
@@ -0,0 +1,14 @@
+"""Disclaimer: This project is experimental, under heavy development, and should not
+be used yet."""
+
+load("@bazel_skylib//:bzl_library.bzl", "bzl_library")
+
+licenses(["notice"])
+
+bzl_library(
+ name = "cc_bindings_from_rust_rule_bzl",
+ srcs = ["cc_bindings_from_rust_rule.bzl"],
+ visibility = [
+ "//:__subpackages__",
+ ],
+)
diff --git a/cc_bindings_from_rs/bazel_support/cc_bindings_from_rust_rule.bzl b/cc_bindings_from_rs/bazel_support/cc_bindings_from_rust_rule.bzl
new file mode 100644
index 0000000..1cc3eaf
--- /dev/null
+++ b/cc_bindings_from_rs/bazel_support/cc_bindings_from_rust_rule.bzl
@@ -0,0 +1,99 @@
+# Part of the Crubit project, under the Apache License v2.0 with LLVM
+# Exceptions. See /LICENSE for license information.
+# SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+
+"""`cc_bindings_from_rust` rule.
+
+Disclaimer: This project is experimental, under heavy development, and should
+not be used yet.
+"""
+
+load(
+ "@rules_rust//rust:rust_common.bzl",
+ "CrateInfo",
+)
+load("@bazel_tools//tools/cpp:toolchain_utils.bzl", "find_cpp_toolchain")
+
+def _generate_bindings(ctx, basename, crate_root, rustc_args):
+ # TODO(b/254097223): Also cover `rs_out_file = ... + "_cc_api_impl.rs"`.
+ h_out_file = ctx.actions.declare_file(basename + "_cc_api.h")
+
+ crubit_args = ctx.actions.args()
+ crubit_args.add("--h-out", h_out_file)
+
+ ctx.actions.run(
+ outputs = [h_out_file],
+ inputs = [crate_root],
+ executable = ctx.executable._cc_bindings_from_rs_tool,
+ mnemonic = "CcBindingsFromRust",
+ progress_message = "Generating C++ bindings from Rust: %s" % h_out_file,
+ arguments = [crubit_args, "--", rustc_args],
+ )
+
+ return h_out_file
+
+def _cc_bindings_from_rust_rule_impl(ctx):
+ basename = ctx.attr.crate.label.name
+ crate_root = ctx.attr.crate[CrateInfo].root
+
+ # TODO(b/258449205): Extract `rustc_args` from the target `crate` (instead
+ # of figuring out the `crate_root` and hard-coding `--crate-type`,
+ # `panic=abort`, etc.). It seems that `BuildInfo` from
+ # @rules_rust//rust/private/providers.bzl is not
+ # exposed publicly?
+ rustc_args = ctx.actions.args()
+ rustc_args.add(crate_root)
+ rustc_args.add("--crate-type", "lib")
+ rustc_args.add("--codegen", "panic=abort")
+
+ h_out_file = _generate_bindings(ctx, basename, crate_root, rustc_args)
+
+ cc_toolchain = find_cpp_toolchain(ctx)
+ feature_configuration = cc_common.configure_features(
+ ctx = ctx,
+ cc_toolchain = cc_toolchain,
+ )
+ (compilation_context, compilation_outputs) = cc_common.compile(
+ name = ctx.label.name,
+ actions = ctx.actions,
+ feature_configuration = feature_configuration,
+ cc_toolchain = cc_toolchain,
+ public_hdrs = [h_out_file],
+ )
+ (linking_context, _) = cc_common.create_linking_context_from_compilation_outputs(
+ name = ctx.label.name,
+ actions = ctx.actions,
+ feature_configuration = feature_configuration,
+ cc_toolchain = cc_toolchain,
+ compilation_outputs = compilation_outputs,
+ linking_contexts = [ctx.attr.crate[CcInfo].linking_context],
+ )
+ return [CcInfo(
+ compilation_context = compilation_context,
+ linking_context = linking_context,
+ )]
+
+# TODO(b/257283134): Register actions via an `aspect`, rather than directly
+# from the `rule` implementation?
+cc_bindings_from_rust = rule(
+ implementation = _cc_bindings_from_rust_rule_impl,
+ doc = "Rule for generating C++ bindings for a Rust library.",
+ attrs = {
+ "crate": attr.label(
+ doc = "Rust library to generate C++ bindings for",
+ allow_files = False,
+ mandatory = True,
+ providers = [CrateInfo],
+ ),
+ "_cc_bindings_from_rs_tool": attr.label(
+ default = Label("//cc_bindings_from_rs:cc_bindings_from_rs_legacy_toolchain_runner.sar"),
+ executable = True,
+ cfg = "exec",
+ allow_single_file = True,
+ ),
+ "_cc_toolchain": attr.label(
+ default = "@bazel_tools//tools/cpp:current_cc_toolchain",
+ ),
+ },
+ fragments = ["cpp"],
+)
diff --git a/cc_bindings_from_rs/test/functions/BUILD b/cc_bindings_from_rs/test/functions/BUILD
index 4ceb53e..ccface3 100644
--- a/cc_bindings_from_rs/test/functions/BUILD
+++ b/cc_bindings_from_rs/test/functions/BUILD
@@ -5,6 +5,10 @@
"@rules_rust//rust:defs.bzl",
"rust_library",
)
+load(
+ "//cc_bindings_from_rs/bazel_support:cc_bindings_from_rust_rule.bzl",
+ "cc_bindings_from_rust",
+)
licenses(["notice"])
@@ -17,37 +21,10 @@
],
)
-alias(
- name = "cc_bindings_from_rs_tool",
- actual = "//cc_bindings_from_rs:cc_bindings_from_rs_legacy_toolchain_runner.sar",
-)
-
-# TODO(b/257283134): Replace `genrule` with a custom `rule`.
-genrule(
- name = "functions_cc_api_genrule",
- testonly = 1,
- srcs = ["functions.rs"],
-
- # TODO(b/254097223): Also cover `functions_cc_api_impl.rs`
- # (wrapping it in a `rust_library` that `functions_cc_api` depends on).
- outs = ["functions_cc_api.h"],
- cmd = """
- $(location :cc_bindings_from_rs_tool) \
- "--h-out=$@" \
- -- \
- $(SRCS) \
- --crate-type=lib \
- --codegen=panic=abort \
- """,
- message = "Running cc_bindings_from_rs",
- tools = [":cc_bindings_from_rs_tool"],
-)
-
-cc_library(
+cc_bindings_from_rust(
name = "functions_cc_api",
testonly = 1,
- hdrs = [":functions_cc_api.h"],
- deps = [":functions"],
+ crate = ":functions",
)
cc_test(