Pass feature flags in from aspect hints down to cc_bindings_from_rs.
This is not completely tested, because bazel unit testing is very troublesome, though I can do it. It's my hope I can get away with integration tests when this is actually used, and golden/unit tests for the trivial stuff.
PiperOrigin-RevId: 672700966
Change-Id: Icc5ad759afa077b832747bef22e6639194a63f46
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
index 06ebc7b..d3c282d 100644
--- 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
@@ -42,6 +42,10 @@
"GeneratedBindingsInfo",
)
load(
+ "//features:crubit_feature_hint.bzl",
+ "find_crubit_features",
+)
+load(
"//rs_bindings_from_cc/bazel_support:compile_rust.bzl",
"compile_rust",
)
@@ -89,7 +93,7 @@
rustc_env: `rustc` environment to use when running `cc_bindings_from_rs`
Returns:
- The GeneratedBindingsInfo provider.
+ A tuple of (GeneratedBindingsInfo, features).
"""
h_out_file = ctx.actions.declare_file(basename + "_cc_api.h")
rs_out_file = ctx.actions.declare_file(basename + "_cc_api_impl.rs")
@@ -108,6 +112,13 @@
for header in dep_bindings_info.headers:
arg = dep_bindings_info.crate_key + "=" + header.short_path
crubit_args.add("--bindings-from-dependency", arg)
+ for feature in dep_bindings_info.features:
+ arg = dep_bindings_info.crate_key + "=" + feature
+ crubit_args.add("--crate-feature", arg)
+
+ features = find_crubit_features(target, ctx)
+ for feature in features:
+ crubit_args.add("--crate-feature", "self=" + feature)
outputs = [h_out_file, rs_out_file]
if ctx.attr._generate_error_report[BuildSettingInfo].value:
@@ -145,11 +156,13 @@
arguments = [args.process_wrapper_flags, "--", ctx.executable._cc_bindings_from_rs_tool.path, crubit_args, "--", args.rustc_flags, "-Cpanic=abort"],
)
- return GeneratedBindingsInfo(
+ generated_bindings_info = GeneratedBindingsInfo(
h_file = h_out_file,
rust_file = rs_out_file,
)
+ return generated_bindings_info, features
+
def _make_cc_info_for_h_out_file(ctx, h_out_file, cc_infos):
"""Creates and returns CcInfo for the generated ..._cc_api.h header file.
@@ -303,7 +316,7 @@
skip_expanding_rustc_env = True,
)
- bindings_info = _generate_bindings(
+ bindings_info, features = _generate_bindings(
ctx,
target,
basename,
@@ -327,6 +340,7 @@
cc_info = cc_info,
crate_key = crate_info.name,
headers = [bindings_info.h_file],
+ features = features,
),
bindings_info,
OutputGroupInfo(out = depset([bindings_info.h_file, bindings_info.rust_file])),
@@ -388,6 +402,9 @@
"_generate_error_report": attr.label(
default = "//cc_bindings_from_rs/bazel_support:generate_error_report",
),
+ "_globally_enabled_features": attr.label(
+ default = "//rs_bindings_from_cc/bazel_support:globally_enabled_features",
+ ),
},
toolchains = [
"@rules_rust//rust:toolchain_type",
diff --git a/cc_bindings_from_rs/bazel_support/providers.bzl b/cc_bindings_from_rs/bazel_support/providers.bzl
index c555f46..6ec0dcc 100644
--- a/cc_bindings_from_rs/bazel_support/providers.bzl
+++ b/cc_bindings_from_rs/bazel_support/providers.bzl
@@ -13,6 +13,7 @@
# flags.
"crate_key": "String with a crate key to use in --other-crate-bindings",
"headers": "A list of C++ headers which correspond to this crate.",
+ "features": "A list of features enabled for the bindings for this crate.",
},
)
diff --git a/cc_bindings_from_rs/bindings.rs b/cc_bindings_from_rs/bindings.rs
index 939f71f..de8f624 100644
--- a/cc_bindings_from_rs/bindings.rs
+++ b/cc_bindings_from_rs/bindings.rs
@@ -30,7 +30,7 @@
use rustc_middle::mir::ConstValue;
use rustc_middle::mir::Mutability;
use rustc_middle::ty::{self, Ty, TyCtxt}; // See <internal link>/ty.html#import-conventions
-use rustc_span::def_id::{DefId, LocalDefId, LocalModDefId, LOCAL_CRATE};
+use rustc_span::def_id::{CrateNum, DefId, LocalDefId, LocalModDefId, LOCAL_CRATE};
use rustc_span::symbol::{kw, sym, Symbol};
use rustc_target::abi::{
Abi, AddressSpace, FieldsShape, Integer, Layout, Pointer, Primitive, Scalar,
@@ -66,7 +66,8 @@
#[input]
fn crate_name_to_include_paths(&self) -> Rc<HashMap<Rc<str>, Vec<CcInclude>>>;
- /// A map from a crate name to the features enabled on that crate.
+ /// A map from a crate name to the features enabled on that crate. The special name `self`
+ /// refers to the current crate.
// TODO(b/271857814): A crate name might not be globally unique - the key needs to also cover
// a "hash" of the crate version and compilation flags.
#[input]
@@ -125,9 +126,22 @@
let top_comment = {
let crate_name = tcx.crate_name(LOCAL_CRATE);
+ let crubit_features = {
+ let mut crubit_features: Vec<&str> = crate_features(db, LOCAL_CRATE)
+ .into_iter()
+ .map(|feature| feature.short_name())
+ .collect();
+ crubit_features.sort();
+ if crubit_features.is_empty() {
+ "<none>".to_string()
+ } else {
+ crubit_features.join(", ")
+ }
+ };
let txt = format!(
"Automatically @generated C++ bindings for the following Rust crate:\n\
- {crate_name}"
+ {crate_name}\n\
+ Features: {crubit_features}"
);
quote! { __COMMENT__ #txt __NEWLINE__ }
};
@@ -164,6 +178,19 @@
Ok(Output { h_body, rs_body })
}
+fn crate_features(
+ db: &dyn BindingsGenerator,
+ krate: CrateNum,
+) -> flagset::FlagSet<crubit_feature::CrubitFeature> {
+ let crate_features = db.crate_name_to_features();
+ let features = if krate == LOCAL_CRATE {
+ crate_features.get("self")
+ } else {
+ crate_features.get(db.tcx().crate_name(krate).as_str())
+ };
+ features.copied().unwrap_or_default()
+}
+
#[derive(Clone, Debug, Default)]
struct CcPrerequisites {
/// Set of `#include`s that a `CcSnippet` depends on. For example if
@@ -4035,7 +4062,8 @@
test_generated_bindings(test_src, |bindings| {
let bindings = bindings.unwrap();
let expected_comment_txt = "Automatically @generated C++ bindings for the following Rust crate:\n\
- rust_out";
+ rust_out\n\
+ Features: <none>";
assert_cc_matches!(
bindings.h_body,
quote! {
diff --git a/cc_bindings_from_rs/cc_bindings_from_rs.rs b/cc_bindings_from_rs/cc_bindings_from_rs.rs
index df50db9..a2ff39f 100644
--- a/cc_bindings_from_rs/cc_bindings_from_rs.rs
+++ b/cc_bindings_from_rs/cc_bindings_from_rs.rs
@@ -375,6 +375,7 @@
"{}\n{}\n{}",
r#"// Automatically @generated C++ bindings for the following Rust crate:
// test_crate
+// Features: <none>
// clang-format off
#pragma once
@@ -409,6 +410,7 @@
&rs_body,
r#"// Automatically @generated C++ bindings for the following Rust crate:
// test_crate
+// Features: <none>
#![allow(improper_ctypes_definitions)]
diff --git a/cc_bindings_from_rs/cmdline.rs b/cc_bindings_from_rs/cmdline.rs
index 44995c5..f792695 100644
--- a/cc_bindings_from_rs/cmdline.rs
+++ b/cc_bindings_from_rs/cmdline.rs
@@ -51,7 +51,8 @@
/// Feature flags enabled for a given crate. Keys are crate names, and
/// values are feature flags. All crates must have their features fully
/// specified, and consistently across rustc invocations, or the
- /// behavior is undefined.
+ /// behavior is undefined. As a special case, the crate name `self`
+ /// refers to the current crate, whose bindings are being generated.
///
/// Example: "--crate-feature=foo=experimental".
#[clap(long = "crate-feature", value_parser = parse_crate_feature,
@@ -273,7 +274,7 @@
[aliases: bindings-from-dependency]
--crate-feature <CRATE_NAME=CRUBIT_FEATURE>
- Feature flags enabled for a given crate. Keys are crate names, and values are feature flags. All crates must have their features fully specified, and consistently across rustc invocations, or the behavior is undefined.
+ Feature flags enabled for a given crate. Keys are crate names, and values are feature flags. All crates must have their features fully specified, and consistently across rustc invocations, or the behavior is undefined. As a special case, the crate name `self` refers to the current crate, whose bindings are being generated.
Example: "--crate-feature=foo=experimental".
diff --git a/cc_bindings_from_rs/test/golden/struct_with_conflicting_fields_and_member_functions_cc_api.h b/cc_bindings_from_rs/test/golden/struct_with_conflicting_fields_and_member_functions_cc_api.h
index 1e4cf89..750ce1f 100644
--- a/cc_bindings_from_rs/test/golden/struct_with_conflicting_fields_and_member_functions_cc_api.h
+++ b/cc_bindings_from_rs/test/golden/struct_with_conflicting_fields_and_member_functions_cc_api.h
@@ -4,6 +4,7 @@
// Automatically @generated C++ bindings for the following Rust crate:
// struct_with_conflicting_fields_and_member_functions_rust
+// Features: experimental, supported
// clang-format off
#pragma once
diff --git a/cc_bindings_from_rs/test/golden/struct_with_conflicting_fields_and_member_functions_cc_api_impl.rs b/cc_bindings_from_rs/test/golden/struct_with_conflicting_fields_and_member_functions_cc_api_impl.rs
index 7ec0563..24ac14b 100644
--- a/cc_bindings_from_rs/test/golden/struct_with_conflicting_fields_and_member_functions_cc_api_impl.rs
+++ b/cc_bindings_from_rs/test/golden/struct_with_conflicting_fields_and_member_functions_cc_api_impl.rs
@@ -4,6 +4,7 @@
// Automatically @generated C++ bindings for the following Rust crate:
// struct_with_conflicting_fields_and_member_functions_rust
+// Features: experimental, supported
#![allow(improper_ctypes_definitions)]
diff --git a/cc_bindings_from_rs/test/golden/type_aliases_cc_api.h b/cc_bindings_from_rs/test/golden/type_aliases_cc_api.h
index 8f94096..7a05a1a 100644
--- a/cc_bindings_from_rs/test/golden/type_aliases_cc_api.h
+++ b/cc_bindings_from_rs/test/golden/type_aliases_cc_api.h
@@ -4,6 +4,7 @@
// Automatically @generated C++ bindings for the following Rust crate:
// type_aliases_rust
+// Features: experimental, supported
// clang-format off
#pragma once
diff --git a/cc_bindings_from_rs/test/golden/type_aliases_cc_api_impl.rs b/cc_bindings_from_rs/test/golden/type_aliases_cc_api_impl.rs
index dd022fb..a15cd1b 100644
--- a/cc_bindings_from_rs/test/golden/type_aliases_cc_api_impl.rs
+++ b/cc_bindings_from_rs/test/golden/type_aliases_cc_api_impl.rs
@@ -4,6 +4,7 @@
// Automatically @generated C++ bindings for the following Rust crate:
// type_aliases_rust
+// Features: experimental, supported
#![allow(improper_ctypes_definitions)]
diff --git a/cc_bindings_from_rs/test/golden/uses_cc_api.h b/cc_bindings_from_rs/test/golden/uses_cc_api.h
index b807fbd..76228d3 100644
--- a/cc_bindings_from_rs/test/golden/uses_cc_api.h
+++ b/cc_bindings_from_rs/test/golden/uses_cc_api.h
@@ -4,6 +4,7 @@
// Automatically @generated C++ bindings for the following Rust crate:
// uses_rust
+// Features: experimental, supported
// clang-format off
#pragma once
diff --git a/cc_bindings_from_rs/test/golden/uses_cc_api_impl.rs b/cc_bindings_from_rs/test/golden/uses_cc_api_impl.rs
index 5605457..00ac247 100644
--- a/cc_bindings_from_rs/test/golden/uses_cc_api_impl.rs
+++ b/cc_bindings_from_rs/test/golden/uses_cc_api_impl.rs
@@ -4,6 +4,7 @@
// Automatically @generated C++ bindings for the following Rust crate:
// uses_rust
+// Features: experimental, supported
#![allow(improper_ctypes_definitions)]
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 28cda46..7143fa3 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
@@ -145,6 +145,7 @@
cc_info = cc_info,
crate_key = dep_variant_info.crate_info.name,
headers = public_hdrs,
+ features = [],
),
]