diff --git a/BUILD.bazel b/BUILD.bazel index 11411d4f1d..1ea1251e62 100644 --- a/BUILD.bazel +++ b/BUILD.bazel @@ -1,5 +1,17 @@ load("@bazel_skylib//:bzl_library.bzl", "bzl_library") -load("//rust:defs.bzl", "capture_clippy_output", "clippy_flags", "error_format", "extra_exec_rustc_flag", "extra_exec_rustc_flags", "extra_rustc_flag", "extra_rustc_flags", "is_proc_macro_dep", "is_proc_macro_dep_enabled") +load( + "//rust:defs.bzl", + "capture_clippy_output", + "clippy_flags", + "error_format", + "extra_exec_rustc_flag", + "extra_exec_rustc_flags", + "extra_rustc_flag", + "extra_rustc_flags", + "is_proc_macro_dep", + "is_proc_macro_dep_enabled", + "output_diagnostics", +) exports_files(["LICENSE"]) @@ -18,6 +30,13 @@ error_format( visibility = ["//visibility:public"], ) +# This setting may be changed from the command line to generate rustc diagnostics. +output_diagnostics( + name = "output_diagnostics", + build_setting_default = False, + visibility = ["//visibility:public"], +) + # This setting may be used to pass extra options to clippy from the command line. # It applies across all targets. clippy_flags( diff --git a/docs/flatten.md b/docs/flatten.md index 9a73478905..7987593e14 100644 --- a/docs/flatten.md +++ b/docs/flatten.md @@ -1379,7 +1379,8 @@ A test rule for performing `rustfmt --check` on a set of targets
CrateInfo(aliases, compile_data, deps, edition, is_test, metadata, name, output, owner, - proc_macro_deps, root, rustc_env, rustc_env_files, srcs, type, wrapped_crate_type) + proc_macro_deps, root, rust_lib_rustc_output, rust_metadata_rustc_output, rustc_env, + rustc_env_files, srcs, type, wrapped_crate_type)A provider containing general Crate information. @@ -1394,12 +1395,14 @@ A provider containing general Crate information. | deps | depset[DepVariantInfo]: This crate's (rust or cc) dependencies' providers. | | edition | str: The edition of this crate. | | is_test | bool: If the crate is being compiled in a test context | -| metadata | File: The rmeta file produced for this crate. It is optional. | +| metadata | File: The output from rustc from producing the output file. It is optional. | | 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 | | proc_macro_deps | depset[DepVariantInfo]: This crate's rust proc_macro dependencies' providers. | | root | File: The source File entrypoint to this crate, eg. lib.rs | +| rust_lib_rustc_output | File: The output from rustc from producing the output file. It is optional. | +| rust_metadata_rustc_output | File: The rmeta file produced for this crate. It is optional. | | rustc_env | Dict[String, String]: Additional
"key": "value"
environment variables to set for rustc. |
| rustc_env_files | [File]: Files containing additional environment variables to set for rustc. |
| srcs | depset[File]: All source Files that are part of the crate. |
diff --git a/docs/providers.md b/docs/providers.md
index 11f77b7d1b..1834ed68c4 100644
--- a/docs/providers.md
+++ b/docs/providers.md
@@ -11,7 +11,8 @@
CrateInfo(aliases, compile_data, deps, edition, is_test, metadata, name, output, owner, - proc_macro_deps, root, rustc_env, rustc_env_files, srcs, type, wrapped_crate_type) + proc_macro_deps, root, rust_lib_rustc_output, rust_metadata_rustc_output, rustc_env, + rustc_env_files, srcs, type, wrapped_crate_type)A provider containing general Crate information. @@ -26,12 +27,14 @@ A provider containing general Crate information. | deps | depset[DepVariantInfo]: This crate's (rust or cc) dependencies' providers. | | edition | str: The edition of this crate. | | is_test | bool: If the crate is being compiled in a test context | -| metadata | File: The rmeta file produced for this crate. It is optional. | +| metadata | File: The output from rustc from producing the output file. It is optional. | | 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 | | proc_macro_deps | depset[DepVariantInfo]: This crate's rust proc_macro dependencies' providers. | | root | File: The source File entrypoint to this crate, eg. lib.rs | +| rust_lib_rustc_output | File: The output from rustc from producing the output file. It is optional. | +| rust_metadata_rustc_output | File: The rmeta file produced for this crate. It is optional. | | rustc_env | Dict[String, String]: Additional
"key": "value"
environment variables to set for rustc. |
| rustc_env_files | [File]: Files containing additional environment variables to set for rustc. |
| srcs | depset[File]: All source Files that are part of the crate. |
diff --git a/rust/defs.bzl b/rust/defs.bzl
index 92c8a77406..24aa32492d 100644
--- a/rust/defs.bzl
+++ b/rust/defs.bzl
@@ -49,6 +49,7 @@ load(
_extra_rustc_flags = "extra_rustc_flags",
_is_proc_macro_dep = "is_proc_macro_dep",
_is_proc_macro_dep_enabled = "is_proc_macro_dep_enabled",
+ _output_diagnostics = "output_diagnostics",
)
load(
"//rust/private:rustdoc.bzl",
@@ -103,6 +104,9 @@ rust_clippy = _rust_clippy
capture_clippy_output = _capture_clippy_output
# See @rules_rust//rust/private:clippy.bzl for a complete description.
+output_diagnostics = _output_diagnostics
+# See @rules_rust//rust/private:rustc.bzl for a complete description.
+
error_format = _error_format
# See @rules_rust//rust/private:rustc.bzl for a complete description.
diff --git a/rust/private/common.bzl b/rust/private/common.bzl
index 20eb40b61d..6c322ae77e 100644
--- a/rust/private/common.bzl
+++ b/rust/private/common.bzl
@@ -49,6 +49,10 @@ def _create_crate_info(**kwargs):
kwargs.update({"wrapped_crate_type": None})
if not "metadata" in kwargs:
kwargs.update({"metadata": None})
+ if not "rust_metadata_rustc_output" in kwargs:
+ kwargs.update({"rust_metadata_rustc_output": None})
+ if not "rust_lib_rustc_output" in kwargs:
+ kwargs.update({"rust_lib_rustc_output": None})
if not "rustc_env_files" in kwargs:
kwargs.update({"rustc_env_files": []})
return CrateInfo(**kwargs)
diff --git a/rust/private/providers.bzl b/rust/private/providers.bzl
index 464444ba93..952a107d26 100644
--- a/rust/private/providers.bzl
+++ b/rust/private/providers.bzl
@@ -22,12 +22,14 @@ CrateInfo = provider(
"deps": "depset[DepVariantInfo]: This crate's (rust or cc) dependencies' providers.",
"edition": "str: The edition of this crate.",
"is_test": "bool: If the crate is being compiled in a test context",
- "metadata": "File: The rmeta file produced for this crate. It is optional.",
+ "metadata": "File: The output from rustc from producing the output file. It is optional.",
"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",
"proc_macro_deps": "depset[DepVariantInfo]: This crate's rust proc_macro dependencies' providers.",
"root": "File: The source File entrypoint to this crate, eg. lib.rs",
+ "rust_lib_rustc_output": "File: The output from rustc from producing the output file. It is optional.",
+ "rust_metadata_rustc_output": "File: The rmeta file produced for this crate. It is optional.",
"rustc_env": "Dict[String, String]: Additional `\"key\": \"value\"` environment variables to set for rustc.",
"rustc_env_files": "[File]: Files containing additional environment variables to set for rustc.",
"srcs": "depset[File]: All source Files that are part of the crate.",
diff --git a/rust/private/rust.bzl b/rust/private/rust.bzl
index 8ae8a0b215..b9eab3ec85 100644
--- a/rust/private/rust.bzl
+++ b/rust/private/rust.bzl
@@ -64,6 +64,9 @@ def _assert_correct_dep_mapping(ctx):
),
)
+def _rustc_output_name(name):
+ return name + ".rustc-output"
+
def _determine_lib_name(name, crate_type, toolchain, lib_hash = None):
"""See https://github.com/bazelbuild/rules_rust/issues/405
@@ -275,14 +278,30 @@ def _rust_library_common(ctx, crate_type):
toolchain,
output_hash,
)
+
rust_lib = ctx.actions.declare_file(rust_lib_name)
+ rust_lib_build_output = None
+ output_diagnostics = ctx.attr._output_diagnostics
+ if ctx.attr._process_wrapper and output_diagnostics:
+ rust_lib_build_output = ctx.actions.declare_file(
+ _rustc_output_name(rust_lib_name),
+ sibling = rust_lib,
+ )
rust_metadata = None
+ rust_metadata_build_output = None
if can_build_metadata(toolchain, ctx, crate_type) and not ctx.attr.disable_pipelining:
+ rust_metadata_name = paths.replace_extension(rust_lib_name, ".rmeta")
+
rust_metadata = ctx.actions.declare_file(
- paths.replace_extension(rust_lib_name, ".rmeta"),
+ rust_metadata_name,
sibling = rust_lib,
)
+ if output_diagnostics:
+ rust_metadata_build_output = ctx.actions.declare_file(
+ _rustc_output_name(rust_metadata_name),
+ sibling = rust_metadata,
+ )
deps = transform_deps(ctx.attr.deps)
proc_macro_deps = transform_deps(ctx.attr.proc_macro_deps + get_import_macro_deps(ctx))
@@ -300,7 +319,9 @@ def _rust_library_common(ctx, crate_type):
proc_macro_deps = depset(proc_macro_deps),
aliases = ctx.attr.aliases,
output = rust_lib,
+ rust_lib_rustc_output = rust_lib_build_output,
metadata = rust_metadata,
+ rust_metadata_rustc_output = rust_metadata_build_output,
edition = get_edition(ctx.attr, toolchain, ctx.label),
rustc_env = ctx.attr.rustc_env,
rustc_env_files = ctx.files.rustc_env_files,
@@ -598,7 +619,7 @@ _common_attrs = {
The order that these files will be processed is unspecified, so
multiple definitions of a particular variable are discouraged.
- Note that the variables here are subject to
+ Note that the variables here are subject to
[workspace status](https://docs.bazel.build/versions/main/user-manual.html#workspace_status)
stamping should the `stamp` attribute be enabled. Stamp variables
should be wrapped in brackets in order to be resolved. E.g.
@@ -611,7 +632,7 @@ _common_attrs = {
List of compiler flags passed to `rustc`.
These strings are subject to Make variable expansion for predefined
- source/output path variables like `$location`, `$execpath`, and
+ source/output path variables like `$location`, `$execpath`, and
`$rootpath`. This expansion is useful if you wish to pass a generated
file of arguments to rustc: `@$(location //package:target)`.
"""),
@@ -673,6 +694,9 @@ _common_attrs = {
"_is_proc_macro_dep_enabled": attr.label(
default = Label("//:is_proc_macro_dep_enabled"),
),
+ "_output_diagnostics": attr.label(
+ default = Label("//:output_diagnostics"),
+ ),
"_process_wrapper": attr.label(
doc = "A process wrapper for running rustc on all platforms.",
default = Label("//util/process_wrapper"),
@@ -723,7 +747,7 @@ _rust_test_attrs = dict({
mandatory = False,
default = True,
doc = dedent("""\
- Whether to use `libtest`. For targets using this flag, individual tests can be run by using the
+ Whether to use `libtest`. For targets using this flag, individual tests can be run by using the
[--test_arg](https://docs.bazel.build/versions/4.0.0/command-line-reference.html#flag--test_arg) flag.
E.g. `bazel test //src:rust_test --test_arg=foo::test::test_fn`.
"""),
diff --git a/rust/private/rustc.bzl b/rust/private/rustc.bzl
index 3a8c43cc77..5f91abb741 100644
--- a/rust/private/rustc.bzl
+++ b/rust/private/rustc.bzl
@@ -52,6 +52,11 @@ ErrorFormatInfo = provider(
fields = {"error_format": "(string) [" + ", ".join(_error_format_values) + "]"},
)
+OutputDiagnosticsInfo = provider(
+ doc = "Save json diagnostics form rustc",
+ fields = {"output_diagnostics": "(bool)"},
+)
+
ExtraRustcFlagsInfo = provider(
doc = "Pass each value as an additional flag to non-exec rustc invocations",
fields = {"extra_rustc_flags": "List[string] Extra flags to pass to rustc in non-exec configuration"},
@@ -855,6 +860,10 @@ def construct_arguments(
if build_metadata:
# Configure process_wrapper to terminate rustc when metadata are emitted
process_wrapper_flags.add("--rustc-quit-on-rmeta", "true")
+ if crate_info.rust_metadata_rustc_output:
+ process_wrapper_flags.add("--output-file", crate_info.rust_metadata_rustc_output.path)
+ elif crate_info.rust_lib_rustc_output:
+ process_wrapper_flags.add("--output-file", crate_info.rust_lib_rustc_output.path)
rustc_flags.add("--error-format=" + error_format)
@@ -1018,6 +1027,8 @@ def rustc_compile_action(
- (DefaultInfo): The output file for this crate, and its runfiles.
"""
build_metadata = getattr(crate_info, "metadata", None)
+ rust_lib_rustc_output = getattr(crate_info, "rust_lib_rustc_output", None)
+ rust_metadata_rustc_output = getattr(crate_info, "rust_metadata_rustc_output", None)
cc_toolchain, feature_configuration = find_cc_toolchain(ctx)
@@ -1096,7 +1107,7 @@ def rustc_compile_action(
build_flags_files = build_flags_files,
force_all_deps_direct = force_all_deps_direct,
stamp = stamp,
- use_json_output = bool(build_metadata),
+ use_json_output = bool(build_metadata) or bool(rust_lib_rustc_output) or bool(rust_metadata_rustc_output),
)
args_metadata = None
@@ -1156,6 +1167,8 @@ def rustc_compile_action(
# The action might generate extra output that we don't want to include in the `DefaultInfo` files.
action_outputs = list(outputs)
+ if rust_lib_rustc_output:
+ action_outputs.append(rust_lib_rustc_output)
# Rustc generates a pdb file (on Windows) or a dsym folder (on macos) so provide it in an output group for crate
# types that benefit from having debug information in a separate file.
@@ -1189,7 +1202,7 @@ def rustc_compile_action(
ctx.actions.run(
executable = ctx.executable._process_wrapper,
inputs = compile_inputs,
- outputs = [build_metadata],
+ outputs = [build_metadata] + [x for x in [rust_metadata_rustc_output] if x],
env = env,
arguments = args_metadata.all,
mnemonic = "RustcMetadata",
@@ -1307,12 +1320,24 @@ def rustc_compile_action(
if toolchain.target_arch != "wasm32":
providers += establish_cc_info(ctx, attr, crate_info, toolchain, cc_toolchain, feature_configuration, interface_library)
+
+ output_group_info = {}
+
if pdb_file:
- providers.append(OutputGroupInfo(pdb_file = depset([pdb_file])))
+ output_group_info["pdb_file"] = depset([pdb_file])
if dsym_folder:
- providers.append(OutputGroupInfo(dsym_folder = depset([dsym_folder])))
+ output_group_info["dsym_folder"] = depset([dsym_folder])
+ if build_metadata:
+ output_group_info["build_metadata"] = depset([build_metadata])
if build_metadata:
- providers.append(OutputGroupInfo(build_metadata = depset([build_metadata])))
+ output_group_info["build_metadata"] = depset([build_metadata])
+ if rust_metadata_rustc_output:
+ output_group_info["rust_metadata_rustc_output"] = depset([rust_metadata_rustc_output])
+ if rust_lib_rustc_output:
+ output_group_info["rust_lib_rustc_output"] = depset([rust_lib_rustc_output])
+
+ if output_group_info:
+ providers.append(OutputGroupInfo(**output_group_info))
return providers
@@ -1823,6 +1848,30 @@ error_format = rule(
build_setting = config.string(flag = True),
)
+def _output_diagnostics_impl(ctx):
+ """Implementation of the `output_diagnostics` rule
+
+ Args:
+ ctx (ctx): The rule's context object
+
+ Returns:
+ list: A list containing the OutputDiagnosticsInfo provider
+ """
+ return [OutputDiagnosticsInfo(output_diagnostics = ctx.build_setting_value)]
+
+output_diagnostics = rule(
+ doc = (
+ "Setting this flag from the command line with `--@rules_rust//:output_diagnostics` " +
+ "makes rules_rust save rustc json output(suitable for consumption by rust-analyzer) in a file. " +
+ "These are accessible via the " +
+ "`rust_metadata_rustc_output`(for pipelined compilation) and `rust_lib_rustc_output` output groups. " +
+ "You can find these either by using something like `find