Use a toolchain to resolve the crubit binary.
Without using toolchains, or some other solution that also spares the build graph to the same extent, C++/Rust interop via Crubit is incompatible with some binaries, because it would introduce an unacceptable increase to the size of the build graph at analysis time.
Before this CL, we used `select()` to find the actual binary that generates the bindings. `select()` is resolved pretty late, and so puts everything from every branch on the dependency graph at analysis-time. Yet production builds literally only take the branch of the `select()` which depends on just a single binary! So, by making this a toolchain, and evaluated sooner (as I understand it), we cut the number of imagined dependencies significantly.
(I am not a bazel expert.)
We can repeat this for the other uses of select in Crubit (ESPECIALLY for the C++ standard library) to cut the dependencies even further, hopefully so that, by the end of the toolchainification, all or almost all analysis-time deps are in fact the real dependencies.
---
This CL does not port over the prebuilt-for-debugging option. That was obsoleted by crubit on demand, so there's no point. It is now deleted.
I'm not 100% sure on code organization here, but overall I'm pretty pleased with how this worked out. I do think it will not be as pretty once we add standard library headers to this (possibly a bunch of toolchains created by a list comprehension), but on the plus side it might mean we can totally kill the is_on_demand bool, so we'll see.
PiperOrigin-RevId: 668800654
Change-Id: I36a5d8c3bff8c77cf15b1abdc07f75b7f9f27055
diff --git a/common/bazel_support/BUILD b/common/bazel_support/BUILD
new file mode 100644
index 0000000..065fbf1
--- /dev/null
+++ b/common/bazel_support/BUILD
@@ -0,0 +1,38 @@
+load("//rs_bindings_from_cc/bazel_support:toolchain.bzl", "rs_bindings_from_cc_toolchain")
+
+package(
+ default_applicable_licenses = ["//:license"],
+ default_visibility = ["//common/bazel_support:__subpackages__"],
+)
+
+# TOOLCHAINS
+# ==========
+#
+# This BUILD file contains all of the Crubit toolchain implementations.
+# The actual registration happens in MODULE.bazel and toolchains/BUILD.
+
+config_setting(
+ name = "use_fake_rs_bindings_from_cc_setting",
+ flag_values = {
+ "//rs_bindings_from_cc/bazel_support:use_actual_bindings_generator": "False",
+ },
+)
+
+config_setting(
+ name = "use_actual_rs_bindings_from_cc_setting",
+ flag_values = {
+ "//rs_bindings_from_cc/bazel_support:use_actual_bindings_generator": "True",
+ },
+)
+
+rs_bindings_from_cc_toolchain(
+ name = "crubit_on_demand_impl",
+ binary = "//rs_bindings_from_cc:rs_bindings_from_cc",
+ is_on_demand = True,
+)
+
+rs_bindings_from_cc_toolchain(
+ name = "crubit_fake_impl",
+ binary = "//rs_bindings_from_cc/bazel_support:fake_rust_bindings_from_cc",
+ is_on_demand = True,
+)
diff --git a/common/bazel_support/toolchains/BUILD b/common/bazel_support/toolchains/BUILD
index 3f0c813..16f03f6 100644
--- a/common/bazel_support/toolchains/BUILD
+++ b/common/bazel_support/toolchains/BUILD
@@ -7,3 +7,21 @@
# Do not add anything to this file except additional toolchain() calls.
package(default_applicable_licenses = ["//:license"])
+
+toolchain(
+ name = "crubit_on_demand",
+ target_settings = [
+ "//common/bazel_support:use_actual_rs_bindings_from_cc_setting",
+ ],
+ toolchain = "//common/bazel_support:crubit_on_demand_impl",
+ toolchain_type = "//rs_bindings_from_cc/bazel_support:toolchain_type",
+)
+
+toolchain(
+ name = "crubit_fake",
+ target_settings = [
+ "//common/bazel_support:use_fake_rs_bindings_from_cc_setting",
+ ],
+ toolchain = "//common/bazel_support:crubit_fake_impl",
+ toolchain_type = "//rs_bindings_from_cc/bazel_support:toolchain_type",
+)
diff --git a/rs_bindings_from_cc/bazel_support/BUILD b/rs_bindings_from_cc/bazel_support/BUILD
index c1c30ce..e6ad6f9 100644
--- a/rs_bindings_from_cc/bazel_support/BUILD
+++ b/rs_bindings_from_cc/bazel_support/BUILD
@@ -117,35 +117,16 @@
deps = ["@bazel_skylib//lib:collections"],
)
-config_setting(
- name = "use_fake_bindings_generator_setting",
- flag_values = {
- ":use_actual_bindings_generator": "False",
- },
-)
-
bool_flag(
name = "use_actual_bindings_generator",
build_setting_default = True,
visibility = ["//visibility:public"],
)
-sh_binary(
+filegroup(
name = "fake_rust_bindings_from_cc",
srcs = ["fake_rust_bindings_from_cc.sh"],
-)
-
-bool_flag(
- name = "use_prebuilt_rs_bindings_from_cc_for_debugging",
- build_setting_default = False,
- visibility = ["//visibility:public"],
-)
-
-config_setting(
- name = "use_prebuilt_rs_bindings_from_cc_setting_for_debugging",
- flag_values = {
- ":use_prebuilt_rs_bindings_from_cc_for_debugging": "True",
- },
+ visibility = ["//:__subpackages__"],
)
alias(
@@ -180,18 +161,13 @@
visibility = ["//visibility:public"],
)
-alias(
- name = "rust_bindings_from_cc_target",
- actual = select({
- ":use_prebuilt_rs_bindings_from_cc_setting": "prebuilt_rs_bindings_from_cc",
- ":use_fake_bindings_generator_setting": ":fake_rust_bindings_from_cc",
- "//conditions:default": "//rs_bindings_from_cc:rs_bindings_from_cc",
- }),
- visibility = ["//visibility:public"],
-)
-
string_list_flag(
name = "globally_enabled_features",
build_setting_default = [],
visibility = ["//visibility:public"],
)
+
+toolchain_type(
+ name = "toolchain_type",
+ visibility = ["//:__subpackages__"],
+)
diff --git a/rs_bindings_from_cc/bazel_support/generate_bindings.bzl b/rs_bindings_from_cc/bazel_support/generate_bindings.bzl
index 05d1b03..9cd0fc5 100644
--- a/rs_bindings_from_cc/bazel_support/generate_bindings.bzl
+++ b/rs_bindings_from_cc/bazel_support/generate_bindings.bzl
@@ -109,6 +109,9 @@
libcxx_include_path = ("include/c++/v1" in cc_toolchain.built_in_include_directories[0]) or \
("fake_path" in cc_toolchain.built_in_include_directories[0])
+ toolchain = ctx.toolchains["@@//rs_bindings_from_cc/bazel_support:toolchain_type"]
+ rs_bindings_from_cc_tool = toolchain.rs_bindings_from_cc_toolchain_info.binary
+
variables = cc_common.create_compile_variables(
feature_configuration = feature_configuration,
cc_toolchain = cc_toolchain,
@@ -130,7 +133,7 @@
),
preprocessor_defines = compilation_context.defines,
variables_extension = {
- "rs_bindings_from_cc_tool": ctx.executable._generator.path,
+ "rs_bindings_from_cc_tool": rs_bindings_from_cc_tool.path,
"rs_bindings_from_cc_flags": rs_bindings_from_cc_flags + _get_hdrs_command_line(public_hdrs) + _get_extra_rs_srcs_command_line(extra_rs_srcs),
"target_args": target_args,
},
@@ -149,7 +152,7 @@
direct = [
ctx.executable._clang_format,
ctx.executable._rustfmt,
- ctx.executable._generator,
+ rs_bindings_from_cc_tool,
] + ctx.files._rustfmt_cfg + extra_rs_srcs,
transitive = [action_inputs],
),
diff --git a/rs_bindings_from_cc/bazel_support/providers.bzl b/rs_bindings_from_cc/bazel_support/providers.bzl
index 2aa24a0..d602a7b 100644
--- a/rs_bindings_from_cc/bazel_support/providers.bzl
+++ b/rs_bindings_from_cc/bazel_support/providers.bzl
@@ -42,3 +42,11 @@
"deps_for_cc_file": "list[CcInfo]",
},
)
+
+RustBindingsFromCcToolchainInfo = provider(
+ doc = """A provider for platform-specific data, provided as a toolchain.""",
+ fields = {
+ "binary": "The label for the rs_bindings_from_cc binary",
+ "is_on_demand": "Whether this is a dynamically built binary or not",
+ },
+)
diff --git a/rs_bindings_from_cc/bazel_support/rust_bindings_from_cc_aspect.bzl b/rs_bindings_from_cc/bazel_support/rust_bindings_from_cc_aspect.bzl
index d06eb22..f36fc0c 100644
--- a/rs_bindings_from_cc/bazel_support/rust_bindings_from_cc_aspect.bzl
+++ b/rs_bindings_from_cc/bazel_support/rust_bindings_from_cc_aspect.bzl
@@ -100,7 +100,9 @@
def _rust_bindings_from_cc_aspect_impl(target, ctx):
# We use a fake generator only when we are building the real one, in order to avoid
# dependency cycles.
- if ctx.executable._generator.basename == "fake_rust_bindings_from_cc":
+ toolchain = ctx.toolchains["@@//rs_bindings_from_cc/bazel_support:toolchain_type"]
+ generator = toolchain.rs_bindings_from_cc_toolchain_info.binary
+ if generator.basename == "fake_rust_bindings_from_cc":
return []
# If this target already provides bindings, we don't need to run the bindings generator.
@@ -236,6 +238,7 @@
toolchains = [
"@rules_rust//rust:toolchain_type",
"@bazel_tools//tools/cpp:toolchain_type",
+ "@@//rs_bindings_from_cc/bazel_support:toolchain_type",
],
fragments = ["cpp", "google_cpp"],
)
diff --git a/rs_bindings_from_cc/bazel_support/rust_bindings_from_cc_utils.bzl b/rs_bindings_from_cc/bazel_support/rust_bindings_from_cc_utils.bzl
index 42a5394..9dbc9e9 100644
--- a/rs_bindings_from_cc/bazel_support/rust_bindings_from_cc_utils.bzl
+++ b/rs_bindings_from_cc/bazel_support/rust_bindings_from_cc_utils.bzl
@@ -152,12 +152,6 @@
"_cc_toolchain": attr.label(
default = "@bazel_tools//tools/cpp:current_cc_toolchain",
),
- "_generator": attr.label(
- default = "@@//rs_bindings_from_cc/bazel_support:rust_bindings_from_cc_target",
- executable = True,
- allow_single_file = True,
- cfg = "exec",
- ),
"_deps_for_bindings": attr.label(
doc = "Dependencies that are needed to compile the generated .cc and .rs file.",
default = "@@//rs_bindings_from_cc/bazel_support:deps_for_bindings",
diff --git a/rs_bindings_from_cc/bazel_support/toolchain.bzl b/rs_bindings_from_cc/bazel_support/toolchain.bzl
new file mode 100644
index 0000000..d770678
--- /dev/null
+++ b/rs_bindings_from_cc/bazel_support/toolchain.bzl
@@ -0,0 +1,32 @@
+# 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
+
+"""Crubit (rs_bindings_from_cc) toolchain."""
+
+load(
+ "@@//rs_bindings_from_cc/bazel_support:providers.bzl",
+ "RustBindingsFromCcToolchainInfo",
+)
+
+def _rs_bindings_from_cc_toolchain_impl(ctx):
+ return [
+ platform_common.ToolchainInfo(
+ rs_bindings_from_cc_toolchain_info = RustBindingsFromCcToolchainInfo(
+ binary = ctx.file.binary,
+ is_on_demand = ctx.attr.is_on_demand,
+ ),
+ ),
+ ]
+
+rs_bindings_from_cc_toolchain = rule(
+ implementation = _rs_bindings_from_cc_toolchain_impl,
+ attrs = {
+ "binary": attr.label(
+ executable = True,
+ allow_single_file = True,
+ cfg = "exec",
+ ),
+ "is_on_demand": attr.bool(),
+ },
+)
diff --git a/rs_bindings_from_cc/bazel_support/toolchain_headers.bzl b/rs_bindings_from_cc/bazel_support/toolchain_headers.bzl
index 6e4dc8b..394be13 100644
--- a/rs_bindings_from_cc/bazel_support/toolchain_headers.bzl
+++ b/rs_bindings_from_cc/bazel_support/toolchain_headers.bzl
@@ -93,6 +93,7 @@
toolchains = [
"@rules_rust//rust:toolchain_type",
"@bazel_tools//tools/cpp:toolchain_type",
+ "@@//rs_bindings_from_cc/bazel_support:toolchain_type",
],
fragments = ["cpp", "google_cpp"],
)