From 2e2cd641e5a41071561def5089ee2f41c6377087 Mon Sep 17 00:00:00 2001 From: "re:fi.64" Date: Wed, 23 Jul 2025 11:03:53 -0500 Subject: [PATCH] Add setting `always_enable_metadata_output_groups` Right now, only library targets provide metadata-related output groups. This makes sense for compilation purposes, but building the metadata is also useful for other things; namely, building *only* the metadata is the fastest way to get diagnostic information for your workspace like `cargo check` does. This PR adds a new setting, `always_enable_metadata_output_groups`, that enables both the `build_metadata` and `rustc_rmeta_output` output groups for non-library targets (such as binaries and tests). That means that the presence of metadata in `CrateInfo` can no longer be used to determine pipelind compilation support, so a new attribute, `metadata_supports_pipelining`, is added for that purpose. As an example of the performance increase, compare a `bazel build` on a binary w/o `--output_groups=rustc_rmeta_output`: ``` INFO: Elapsed time: 2.247s, Critical Path: 2.11s ``` to with it: ``` INFO: Elapsed time: 1.034s, Critical Path: 0.90s ``` --- extensions/prost/private/prost.bzl | 20 ++- extensions/protobuf/proto.bzl | 20 ++- rust/private/common.bzl | 2 + rust/private/providers.bzl | 13 ++ rust/private/rust.bzl | 54 +++++++- rust/private/rustc.bzl | 42 +++++- rust/private/utils.bzl | 49 ++++++- rust/settings/BUILD.bazel | 3 + rust/settings/settings.bzl | 13 ++ test/unit/metadata_output_groups/BUILD.bazel | 4 + test/unit/metadata_output_groups/bin.rs | 1 + test/unit/metadata_output_groups/lib.rs | 1 + test/unit/metadata_output_groups/macro.rs | 6 + .../metadata_output_groups.bzl | 122 ++++++++++++++++++ test/unit/metadata_output_groups/unit.rs | 5 + test/unit/pipelined_compilation/wrap.bzl | 8 ++ 16 files changed, 346 insertions(+), 17 deletions(-) create mode 100644 test/unit/metadata_output_groups/BUILD.bazel create mode 100644 test/unit/metadata_output_groups/bin.rs create mode 100644 test/unit/metadata_output_groups/lib.rs create mode 100644 test/unit/metadata_output_groups/macro.rs create mode 100644 test/unit/metadata_output_groups/metadata_output_groups.bzl create mode 100644 test/unit/metadata_output_groups/unit.rs diff --git a/extensions/prost/private/prost.bzl b/extensions/prost/private/prost.bzl index 93bafeebf8..25026eb261 100644 --- a/extensions/prost/private/prost.bzl +++ b/extensions/prost/private/prost.bzl @@ -18,7 +18,12 @@ load("@rules_rust//rust/private:rust_analyzer.bzl", "write_rust_analyzer_spec_fi load("@rules_rust//rust/private:rustc.bzl", "rustc_compile_action") # buildifier: disable=bzl-visibility -load("@rules_rust//rust/private:utils.bzl", "can_build_metadata") +load( + "@rules_rust//rust/private:utils.bzl", + "can_build_metadata", + "can_use_metadata_for_pipelining", + "generate_output_diagnostics", +) load("//:providers.bzl", "ProstProtoInfo") load(":prost_transform.bzl", "ProstTransformInfo") @@ -181,6 +186,8 @@ def _compile_rust( lib = ctx.actions.declare_file(lib_name) rmeta = None + rustc_rmeta_output = None + metadata_supports_pipelining = False if can_build_metadata(toolchain, ctx, "rlib"): rmeta_name = "{prefix}{name}-{lib_hash}{extension}".format( @@ -190,6 +197,8 @@ def _compile_rust( extension = ".rmeta", ) rmeta = ctx.actions.declare_file(rmeta_name) + rustc_rmeta_output = generate_output_diagnostics(ctx, rmeta) + metadata_supports_pipelining = can_use_metadata_for_pipelining(toolchain, "rlib") providers = rustc_compile_action( ctx = ctx, @@ -205,6 +214,8 @@ def _compile_rust( aliases = {}, output = lib, metadata = rmeta, + metadata_supports_pipelining = metadata_supports_pipelining, + rustc_rmeta_output = rustc_rmeta_output, edition = edition, is_test = False, rustc_env = {}, @@ -373,7 +384,12 @@ rust_prost_aspect = aspect( executable = True, default = Label("//private:protoc_wrapper"), ), - } | RUSTC_ATTRS, + } | RUSTC_ATTRS | { + # Need to override this attribute to explicitly set the workspace. + "_always_enable_metadata_output_groups": attr.label( + default = Label("@rules_rust//rust/settings:always_enable_metadata_output_groups"), + ), + }, fragments = ["cpp"], toolchains = [ TOOLCHAIN_TYPE, diff --git a/extensions/protobuf/proto.bzl b/extensions/protobuf/proto.bzl index 08bbb4453c..da74ae7e84 100644 --- a/extensions/protobuf/proto.bzl +++ b/extensions/protobuf/proto.bzl @@ -20,7 +20,16 @@ load("@rules_proto//proto:defs.bzl", "ProtoInfo") load("@rules_rust//rust/private:rustc.bzl", "rustc_compile_action") # buildifier: disable=bzl-visibility -load("@rules_rust//rust/private:utils.bzl", "can_build_metadata", "compute_crate_name", "determine_output_hash", "find_toolchain", "transform_deps") +load( + "@rules_rust//rust/private:utils.bzl", + "can_build_metadata", + "can_use_metadata_for_pipelining", + "compute_crate_name", + "determine_output_hash", + "find_toolchain", + "generate_output_diagnostics", + "transform_deps", +) load( "//:toolchain.bzl", _generate_proto = "rust_generate_proto", @@ -194,12 +203,16 @@ def _rust_proto_compile(protos, descriptor_sets, imports, crate_name, ctx, is_gr output_hash, )) rust_metadata = None + rustc_rmeta_output = None + metadata_supports_pipelining = False if can_build_metadata(toolchain, ctx, "rlib"): rust_metadata = ctx.actions.declare_file("%s/lib%s-%s.rmeta" % ( output_dir, crate_name, output_hash, )) + rustc_rmeta_output = generate_output_diagnostics(ctx, rust_metadata) + metadata_supports_pipelining = can_use_metadata_for_pipelining(toolchain, "rlib") # Gather all dependencies for compilation compile_action_deps = depset( @@ -223,6 +236,8 @@ def _rust_proto_compile(protos, descriptor_sets, imports, crate_name, ctx, is_gr aliases = {}, output = rust_lib, metadata = rust_metadata, + metadata_supports_pipelining = metadata_supports_pipelining, + rustc_rmeta_output = rustc_rmeta_output, edition = proto_toolchain.edition, rustc_env = {}, is_test = False, @@ -311,6 +326,9 @@ rust_proto_library = rule( file of arguments to rustc: `@$(location //package:target)`. """, ), + "_always_enable_metadata_output_groups": attr.label( + default = Label("@rules_rust//rust/settings:always_enable_metadata_output_groups"), + ), "_optional_output_wrapper": attr.label( executable = True, cfg = "exec", diff --git a/rust/private/common.bzl b/rust/private/common.bzl index cc38127bfa..24badaa1c6 100644 --- a/rust/private/common.bzl +++ b/rust/private/common.bzl @@ -51,6 +51,8 @@ def _create_crate_info(**kwargs): kwargs.update({"wrapped_crate_type": None}) if not "metadata" in kwargs: kwargs.update({"metadata": None}) + if not "metadata_supports_pipelining" in kwargs: + kwargs.update({"metadata_supports_pipelining": False}) if not "rustc_rmeta_output" in kwargs: kwargs.update({"rustc_rmeta_output": None}) if not "rustc_output" in kwargs: diff --git a/rust/private/providers.bzl b/rust/private/providers.bzl index 5c47bf14cb..aef2552746 100644 --- a/rust/private/providers.bzl +++ b/rust/private/providers.bzl @@ -25,6 +25,8 @@ CrateInfo = provider( "edition": "str: The edition of this crate.", "is_test": "bool: If the crate is being compiled in a test context", "metadata": "File: The output from rustc from producing the output file. It is optional.", + "metadata_supports_pipelining": "bool: If the metadata in 'metadata' (if present) is " + + "usable for pipelined compilation.", "name": "str: The name of this crate.", "output": "File: The output File that will be produced, depends on crate type.", "owner": "Label: The label of the target that produced this CrateInfo", @@ -98,6 +100,17 @@ DepVariantInfo = provider( }, ) +AlwaysEnableMetadataOutputGroupsInfo = provider( + doc = ( + "Enable the 'metadata' and 'rustc_rmeta_output' groups for all targets, " + + "even if not a library or if pipelining is disabled" + ), + fields = { + "always_enable_metadata_output_groups": ("bool: Whether or not to always enable " + + "metadata-related output groups"), + }, +) + RustcOutputDiagnosticsInfo = provider( doc = ( "Save json diagnostics from rustc. Json diagnostics are able to be " + diff --git a/rust/private/rust.bzl b/rust/private/rust.bzl index dba253b1c0..1a1af19d1e 100644 --- a/rust/private/rust.bzl +++ b/rust/private/rust.bzl @@ -28,6 +28,7 @@ load("//rust/private:rustc.bzl", "rustc_compile_action") load( "//rust/private:utils.bzl", "can_build_metadata", + "can_use_metadata_for_pipelining", "compute_crate_name", "crate_root_src", "dedent", @@ -177,12 +178,22 @@ def _rust_library_common(ctx, crate_type): rust_lib = ctx.actions.declare_file(rust_lib_name) rust_metadata = None rustc_rmeta_output = None - if can_build_metadata(toolchain, ctx, crate_type) and not ctx.attr.disable_pipelining: + metadata_supports_pipelining = False + if can_build_metadata( + toolchain, + ctx, + crate_type, + disable_pipelining = getattr(ctx.attr, "disable_pipelining", False), + ): rust_metadata = ctx.actions.declare_file( paths.replace_extension(rust_lib_name, ".rmeta"), sibling = rust_lib, ) rustc_rmeta_output = generate_output_diagnostics(ctx, rust_metadata) + metadata_supports_pipelining = ( + can_use_metadata_for_pipelining(toolchain, crate_type) and + not ctx.attr.disable_pipelining + ) deps = transform_deps(ctx.attr.deps) proc_macro_deps = transform_deps(ctx.attr.proc_macro_deps + get_import_macro_deps(ctx)) @@ -203,6 +214,7 @@ def _rust_library_common(ctx, crate_type): output = rust_lib, rustc_output = generate_output_diagnostics(ctx, rust_lib), metadata = rust_metadata, + metadata_supports_pipelining = metadata_supports_pipelining, rustc_rmeta_output = rustc_rmeta_output, edition = get_edition(ctx.attr, toolchain, ctx.label), rustc_env = ctx.attr.rustc_env, @@ -242,6 +254,15 @@ def _rust_binary_impl(ctx): crate_root = crate_root_src(ctx.attr.name, ctx.attr.crate_name, ctx.files.srcs, ctx.attr.crate_type) srcs, compile_data, crate_root = transform_sources(ctx, ctx.files.srcs, ctx.files.compile_data, crate_root) + rust_metadata = None + rustc_rmeta_output = None + if can_build_metadata(toolchain, ctx, ctx.attr.crate_type): + rust_metadata = ctx.actions.declare_file( + paths.replace_extension("lib" + crate_name, ".rmeta"), + sibling = output, + ) + rustc_rmeta_output = generate_output_diagnostics(ctx, rust_metadata) + providers = rustc_compile_action( ctx = ctx, attr = ctx.attr, @@ -256,6 +277,8 @@ def _rust_binary_impl(ctx): aliases = ctx.attr.aliases, output = output, rustc_output = generate_output_diagnostics(ctx, output), + metadata = rust_metadata, + rustc_rmeta_output = rustc_rmeta_output, edition = get_edition(ctx.attr, toolchain, ctx.label), rustc_env = ctx.attr.rustc_env, rustc_env_files = ctx.files.rustc_env_files, @@ -337,6 +360,15 @@ def _rust_test_impl(ctx): ), ) + rust_metadata = None + rustc_rmeta_output = None + if can_build_metadata(toolchain, ctx, crate_type): + rust_metadata = ctx.actions.declare_file( + paths.replace_extension("lib" + crate_name, ".rmeta"), + sibling = output, + ) + rustc_rmeta_output = generate_output_diagnostics(ctx, rust_metadata) + # Need to consider all src files together when transforming srcs = depset(ctx.files.srcs, transitive = [crate.srcs]).to_list() compile_data = depset(ctx.files.compile_data, transitive = [crate.compile_data]).to_list() @@ -371,6 +403,8 @@ def _rust_test_impl(ctx): aliases = aliases, output = output, rustc_output = generate_output_diagnostics(ctx, output), + metadata = rust_metadata, + rustc_rmeta_output = rustc_rmeta_output, edition = crate.edition, rustc_env = rustc_env, rustc_env_files = rustc_env_files, @@ -381,6 +415,8 @@ def _rust_test_impl(ctx): owner = ctx.label, ) else: + crate_name = compute_crate_name(ctx.workspace_name, ctx.label, toolchain, ctx.attr.crate_name) + crate_root = getattr(ctx.file, "crate_root", None) if not crate_root: @@ -402,6 +438,15 @@ def _rust_test_impl(ctx): ), ) + rust_metadata = None + rustc_rmeta_output = None + if can_build_metadata(toolchain, ctx, crate_type): + rust_metadata = ctx.actions.declare_file( + paths.replace_extension("lib" + crate_name, ".rmeta"), + sibling = output, + ) + rustc_rmeta_output = generate_output_diagnostics(ctx, rust_metadata) + data_paths = depset(direct = getattr(ctx.attr, "data", [])).to_list() rustc_env = expand_dict_value_locations( ctx, @@ -412,7 +457,7 @@ def _rust_test_impl(ctx): # Target is a standalone crate. Build the test binary as its own crate. crate_info_dict = dict( - name = compute_crate_name(ctx.workspace_name, ctx.label, toolchain, ctx.attr.crate_name), + name = crate_name, type = crate_type, root = crate_root, srcs = depset(srcs), @@ -421,6 +466,8 @@ def _rust_test_impl(ctx): aliases = ctx.attr.aliases, output = output, rustc_output = generate_output_diagnostics(ctx, output), + metadata = rust_metadata, + rustc_rmeta_output = rustc_rmeta_output, edition = get_edition(ctx.attr, toolchain, ctx.label), rustc_env = rustc_env, rustc_env_files = ctx.files.rustc_env_files, @@ -534,6 +581,9 @@ def _stamp_attribute(default_value): # Internal attributes core to Rustc actions. RUSTC_ATTRS = { + "_always_enable_metadata_output_groups": attr.label( + default = Label("//rust/settings:always_enable_metadata_output_groups"), + ), "_error_format": attr.label( default = Label("//rust/settings:error_format"), ), diff --git a/rust/private/rustc.bzl b/rust/private/rustc.bzl index 2643ac01f7..2bc6df1e7c 100644 --- a/rust/private/rustc.bzl +++ b/rust/private/rustc.bzl @@ -27,7 +27,15 @@ load("@rules_cc//cc/common:cc_info.bzl", "CcInfo") load(":common.bzl", "rust_common") load(":compat.bzl", "abs") load(":lto.bzl", "construct_lto_arguments") -load(":providers.bzl", "AllocatorLibrariesImplInfo", "AllocatorLibrariesInfo", "LintsInfo", "RustcOutputDiagnosticsInfo", _BuildInfo = "BuildInfo") +load( + ":providers.bzl", + "AllocatorLibrariesImplInfo", + "AllocatorLibrariesInfo", + "AlwaysEnableMetadataOutputGroupsInfo", + "LintsInfo", + "RustcOutputDiagnosticsInfo", + _BuildInfo = "BuildInfo", +) load(":rustc_resource_set.bzl", "get_rustc_resource_set", "is_codegen_units_enabled") load(":stamp.bzl", "is_stamping_enabled") load( @@ -296,7 +304,7 @@ def collect_deps( # If it doesn't (for example a custom library that exports crate_info), # we depend on crate_info.output. depend_on = crate_info.metadata - if not crate_info.metadata: + if not crate_info.metadata or not crate_info.metadata_supports_pipelining: depend_on = crate_info.output # If this dependency is a proc_macro, it still can be used for lib crates @@ -1986,7 +1994,7 @@ def _crate_to_link_flag_metadata(crate): crate_info = crate lib_or_meta = crate_info.metadata - if not crate_info.metadata: + if not crate_info.metadata or not crate_info.metadata_supports_pipelining: lib_or_meta = crate_info.output return ["--extern={}={}".format(name, lib_or_meta.path)] @@ -2301,6 +2309,30 @@ def get_error_format(attr, attr_name): return getattr(attr, attr_name)[ErrorFormatInfo].error_format return "human" +def _always_enable_metadata_output_groups_impl(ctx): + """Implementation of the `always_enable_metadata_output_groups` rule + + Args: + ctx (ctx): The rule's context object + + Returns: + list: A list containing the AlwaysEnableMetadataOutputGroupsInfo provider + """ + return [AlwaysEnableMetadataOutputGroupsInfo( + always_enable_metadata_output_groups = ctx.build_setting_value, + )] + +always_enable_metadata_output_groups = rule( + doc = ( + "Setting this flag from the command line with `--@rules_rust//rust/settings:always_enable_metadata_output_groups` " + + "will cause all rules to generate the `metadata` and `rustc_rmeta_output` output groups, " + + "rather than the default behavior of only generated them for libraries when pipelined " + + "compilation is enabled." + ), + implementation = _always_enable_metadata_output_groups_impl, + build_setting = config.bool(flag = True), +) + def _rustc_output_diagnostics_impl(ctx): """Implementation of the `rustc_output_diagnostics` rule @@ -2318,8 +2350,8 @@ rustc_output_diagnostics = rule( doc = ( "Setting this flag from the command line with `--@rules_rust//rust/settings:rustc_output_diagnostics` " + "makes rules_rust save rustc json output(suitable for consumption by rust-analyzer) in a file. " + - "These are accessible via the " + - "`rustc_rmeta_output`(for pipelined compilation) and `rustc_output` output groups. " + + "These are accessible via the `rustc_rmeta_output` (for pipelined compilation or if " + + "`always_enable_metadata_output_groups` is enabled) and `rustc_output` output groups. " + "You can find these using `bazel cquery`" ), implementation = _rustc_output_diagnostics_impl, diff --git a/rust/private/utils.bzl b/rust/private/utils.bzl index 0bb9123c75..c2a8f236e6 100644 --- a/rust/private/utils.bzl +++ b/rust/private/utils.bzl @@ -19,7 +19,16 @@ load("@rules_cc//cc:find_cc_toolchain.bzl", find_rules_cc_toolchain = "find_cc_t load("@rules_cc//cc/common:cc_common.bzl", "cc_common") load("@rules_cc//cc/common:cc_info.bzl", "CcInfo") load(":compat.bzl", "abs") -load(":providers.bzl", "BuildInfo", "CrateGroupInfo", "CrateInfo", "DepInfo", "DepVariantInfo", "RustcOutputDiagnosticsInfo") +load( + ":providers.bzl", + "AlwaysEnableMetadataOutputGroupsInfo", + "BuildInfo", + "CrateGroupInfo", + "CrateInfo", + "DepInfo", + "DepVariantInfo", + "RustcOutputDiagnosticsInfo", +) UNSUPPORTED_FEATURES = [ "thin_lto", @@ -679,24 +688,50 @@ def _replace_all(string, substitutions): return string -def can_build_metadata(toolchain, ctx, crate_type): - """Can we build metadata for this rust_library? +def can_build_metadata(toolchain, ctx, crate_type, *, disable_pipelining = False): + """Can we build metadata for the target built using this context? Args: toolchain (toolchain): The rust toolchain ctx (ctx): The rule's context object - crate_type (String): one of lib|rlib|dylib|staticlib|cdylib|proc-macro + crate_type (String): The rule's crate type + disable_pipelining: Does the rule have pipelining explicitly disabled? Returns: bool: whether we can build metadata for this rule. """ + # Building metadata requires that: + # 1) process_wrapper is enabled (this is disabled when compiling process_wrapper itself) + # 2) either: + # * always_enable_metadata_output_groups is set + # * this target can use metadata for pipelined compilation + return bool(ctx.attr._process_wrapper) and ( + ctx.attr._always_enable_metadata_output_groups[AlwaysEnableMetadataOutputGroupsInfo].always_enable_metadata_output_groups or + (not disable_pipelining and + can_use_metadata_for_pipelining(toolchain, crate_type)) + ) + +def can_use_metadata_for_pipelining(toolchain, crate_type): + """Can we use metadata from this rust_library for pipelined compilation? + + This does not include whether or not metadata itself can be generated, which + is covered instead by can_build_metadata. + + Args: + toolchain (toolchain): The rust toolchain + crate_type (String): one of lib|rlib|dylib|staticlib|cdylib|proc-macro + + Returns: + bool: whether we can use the metadata for pipelined compilation. + """ + # In order to enable pipelined compilation we require that: # 1) The _pipelined_compilation flag is enabled, - # 2) process_wrapper is enabled (this is disabled when compiling process_wrapper itself), - # 3) the crate_type is rlib or lib. + # 2) the crate_type is rlib or lib. + # This is *in addition* to the checks in can_build_metadata (i.e. that + # process_wrapper is enabled). return toolchain._pipelined_compilation and \ - ctx.attr._process_wrapper and \ crate_type in ("rlib", "lib") def crate_root_src(name, crate_name, srcs, crate_type): diff --git a/rust/settings/BUILD.bazel b/rust/settings/BUILD.bazel index 0889018d6a..194b12fb8a 100644 --- a/rust/settings/BUILD.bazel +++ b/rust/settings/BUILD.bazel @@ -1,6 +1,7 @@ load("@bazel_skylib//:bzl_library.bzl", "bzl_library") load( ":settings.bzl", + "always_enable_metadata_output_groups", "capture_clippy_output", "clippy_error_format", "clippy_flag", @@ -52,6 +53,8 @@ bzl_library( ], ) +always_enable_metadata_output_groups() + capture_clippy_output() clippy_flag() diff --git a/rust/settings/settings.bzl b/rust/settings/settings.bzl index 272bf7eed8..6934232e43 100644 --- a/rust/settings/settings.bzl +++ b/rust/settings/settings.bzl @@ -18,6 +18,7 @@ load( load("//rust/private:lto.bzl", "rust_lto_flag") load( "//rust/private:rustc.bzl", + _always_enable_metadata_output_groups = "always_enable_metadata_output_groups", _error_format = "error_format", _extra_exec_rustc_flag = "extra_exec_rustc_flag", _extra_exec_rustc_flags = "extra_exec_rustc_flags", @@ -321,6 +322,18 @@ def incompatible_change_clippy_error_format(): issue = "https://github.com/bazelbuild/rules_rust/issues/3494", ) +# buildifier: disable=unnamed-macro +def always_enable_metadata_output_groups(): + """A flag to enable the `always_enable_metadata_output_groups` setting. + + If this flag is true, all rules will support the `metadata` and + `rustc_rmeta_output` output groups.""" + _always_enable_metadata_output_groups( + name = "always_enable_metadata_output_groups", + build_setting_default = False, + visibility = ["//visibility:public"], + ) + # buildifier: disable=unnamed-macro def rustc_output_diagnostics(): """This setting may be changed from the command line to generate rustc diagnostics. diff --git a/test/unit/metadata_output_groups/BUILD.bazel b/test/unit/metadata_output_groups/BUILD.bazel new file mode 100644 index 0000000000..d3adb99b8e --- /dev/null +++ b/test/unit/metadata_output_groups/BUILD.bazel @@ -0,0 +1,4 @@ +load(":metadata_output_groups.bzl", "metadata_output_groups_test_suite") + +############################ UNIT TESTS ############################# +metadata_output_groups_test_suite(name = "metadata_output_groups_test_suite") diff --git a/test/unit/metadata_output_groups/bin.rs b/test/unit/metadata_output_groups/bin.rs new file mode 100644 index 0000000000..f328e4d9d0 --- /dev/null +++ b/test/unit/metadata_output_groups/bin.rs @@ -0,0 +1 @@ +fn main() {} diff --git a/test/unit/metadata_output_groups/lib.rs b/test/unit/metadata_output_groups/lib.rs new file mode 100644 index 0000000000..b76b4321d6 --- /dev/null +++ b/test/unit/metadata_output_groups/lib.rs @@ -0,0 +1 @@ +pub fn foo() {} diff --git a/test/unit/metadata_output_groups/macro.rs b/test/unit/metadata_output_groups/macro.rs new file mode 100644 index 0000000000..035c76101a --- /dev/null +++ b/test/unit/metadata_output_groups/macro.rs @@ -0,0 +1,6 @@ +use proc_macro::TokenStream; + +#[proc_macro_attribute] +pub fn noop(_attr: TokenStream, item: TokenStream) -> TokenStream { + item +} diff --git a/test/unit/metadata_output_groups/metadata_output_groups.bzl b/test/unit/metadata_output_groups/metadata_output_groups.bzl new file mode 100644 index 0000000000..ec89e0f132 --- /dev/null +++ b/test/unit/metadata_output_groups/metadata_output_groups.bzl @@ -0,0 +1,122 @@ +"""Unittests for rust rules.""" + +load("@bazel_skylib//lib:unittest.bzl", "analysistest", "asserts") +load("//rust:defs.bzl", "rust_binary", "rust_library", "rust_proc_macro", "rust_test") + +def _metadata_output_groups_present_test_impl(ctx): + env = analysistest.begin(ctx) + tut = analysistest.target_under_test(env) + + output_groups = tut[OutputGroupInfo] + build_metadata = output_groups.build_metadata.to_list() + rustc_rmeta_output = output_groups.rustc_rmeta_output.to_list() + + asserts.equals(env, 1, len(build_metadata), "Expected 1 build_metadata file") + asserts.true( + build_metadata[0].basename.endswith(".rmeta"), + "Expected %s to end with .rmeta" % build_metadata[0], + ) + + asserts.equals(env, 1, len(rustc_rmeta_output), "Expected 1 rustc_rmeta_output file") + asserts.true( + rustc_rmeta_output[0].basename.endswith(".rustc-output"), + "Expected %s to end with .rustc-output" % rustc_rmeta_output[0], + ) + + return analysistest.end(env) + +def _metadata_output_groups_missing_test_impl(ctx): + env = analysistest.begin(ctx) + tut = analysistest.target_under_test(env) + + output_groups = tut[OutputGroupInfo] + asserts.false(env, hasattr(output_groups, "build_metadata"), "Expected no build_metadata output group") + asserts.false(env, hasattr(output_groups, "rustc_rmeta_output"), "Expected no rustc_rmeta_output output group") + + return analysistest.end(env) + +metadata_output_groups_present_test = analysistest.make( + _metadata_output_groups_present_test_impl, + config_settings = { + str(Label("//rust/settings:always_enable_metadata_output_groups")): True, + str(Label("//rust/settings:rustc_output_diagnostics")): True, + }, +) + +metadata_output_groups_missing_test = analysistest.make( + _metadata_output_groups_missing_test_impl, +) + +def _output_groups_test(*, always_enable): + suffix = "_with_metadata" if always_enable else "_without_metadata" + + rust_binary( + name = "bin" + suffix, + srcs = ["bin.rs"], + edition = "2021", + ) + + rust_library( + name = "lib" + suffix, + srcs = ["lib.rs"], + edition = "2021", + ) + + rust_proc_macro( + name = "macro" + suffix, + srcs = ["macro.rs"], + edition = "2021", + ) + + rust_test( + name = "unit" + suffix, + srcs = ["unit.rs"], + edition = "2021", + ) + + if always_enable: + test = metadata_output_groups_present_test + else: + test = metadata_output_groups_missing_test + + test( + name = "bin_test" + suffix, + target_under_test = ":bin" + suffix, + ) + + test( + name = "lib_test" + suffix, + target_under_test = ":lib" + suffix, + ) + + test( + name = "macro_test" + suffix, + target_under_test = ":macro" + suffix, + ) + + test( + name = "unit_test" + suffix, + target_under_test = ":unit" + suffix, + ) + + return [ + ":bin_test" + suffix, + ":lib_test" + suffix, + ":macro_test" + suffix, + ":unit_test" + suffix, + ] + +def metadata_output_groups_test_suite(name): + """Entry-point macro called from the BUILD file. + + Args: + name: Name of the macro. + """ + tests = [] + tests.extend(_output_groups_test(always_enable = True)) + tests.extend(_output_groups_test(always_enable = False)) + + native.test_suite( + name = name, + tests = tests, + ) diff --git a/test/unit/metadata_output_groups/unit.rs b/test/unit/metadata_output_groups/unit.rs new file mode 100644 index 0000000000..c69771ebd3 --- /dev/null +++ b/test/unit/metadata_output_groups/unit.rs @@ -0,0 +1,5 @@ +#[cfg(test)] +mod tests { + #[test] + fn test_foo() {} +} diff --git a/test/unit/pipelined_compilation/wrap.bzl b/test/unit/pipelined_compilation/wrap.bzl index eef7eafffe..8b461a3f62 100644 --- a/test/unit/pipelined_compilation/wrap.bzl +++ b/test/unit/pipelined_compilation/wrap.bzl @@ -8,6 +8,9 @@ load("//rust/private:providers.bzl", "BuildInfo", "CrateInfo", "DepInfo", "DepVa # buildifier: disable=bzl-visibility load("//rust/private:rustc.bzl", "rustc_compile_action") +# buildifier: disable=bzl-visibility +load("//rust/private:utils.bzl", "can_use_metadata_for_pipelining") + _CONTENT = """\ // crate_name: {} use to_wrap::to_wrap; @@ -70,6 +73,8 @@ def _wrap_impl(ctx): aliases = {}, output = rust_lib, metadata = rust_metadata, + metadata_supports_pipelining = can_use_metadata_for_pipelining(toolchain, crate_type) and + ctx.attr.generate_metadata, owner = ctx.label, edition = "2018", compile_data = depset([]), @@ -86,6 +91,9 @@ wrap = rule( "crate_name": attr.string(), "generate_metadata": attr.bool(default = False), "target": attr.label(), + "_always_enable_metadata_output_groups": attr.label( + default = Label("//rust/settings:always_enable_metadata_output_groups"), + ), "_error_format": attr.label( default = Label("//rust/settings:error_format"), ),